Spec-Zone.ru › C++

Объявление класса

Классы — это определяемые пользователем типы, определённые спецификатором класса, который появляется в decl-specifier-seq синтаксиса объявления.

Синтаксис

Спецификатор класса имеет следующий синтаксис:

class-key attr (необязательно) class-head-name final(необязательно) base-clause (необязательно) { member-specification } (1)
class-key attr (необязательно) base-clause (необязательно) { member-specification } (2)
1) Определение именованного класса
2) Определение безымянного класса
class-key - один из class, struct и union. Ключевые слова class и struct идентичны, за исключением по умолчанию доступа к членам и по умолчанию доступа к базовому классу. Если это union, объявление вводит тип объединения.
attr - (с C++11) любое количество атрибутов, может включать спецификатор alignas
class-head-name - имя класса, которое определяется, необязательно квалифицированное
final - (с C++11) если присутствует, класс не может быть унаследован
base-clause - список одного или нескольких базовых классов и модели наследования, используемой для каждого (см. производный класс)
member-specification - список спецификаторов доступа, объявлений и определений членов объекта и членов функции (см. ниже)

Объявление вперёд

Объявление следующей формы

class-key attr identifier ;

Объявляет тип класса, который будет определён позже в этом области видимости. До тех пор, пока определение не появится, у этого имени класса есть неполный тип. Это позволяет классам ссылаться друг на друга:

class Vector; // forward declaration
 
class Matrix
{
    // ...
    friend Vector operator*(const Matrix&, const Vector&);
};
 
class Vector
{
    // ...
    friend Vector operator*(const Matrix&, const Vector&);
};

и если определённый файл исходного кода использует только указатели и ссылки на класс, это позволяет уменьшить зависимости #include:

// In MyStruct.h
#include <iosfwd> // contains forward declaration of std::ostream
 
struct MyStruct
{
    int value;
    friend std::ostream& operator<<(std::ostream& os, const S& s);
    // definition provided in MyStruct.cpp file which uses #include <ostream>
};

Если объявление вперёд появляется в локальной области видимости, оно скрывает ранее объявленный класс, переменную, функцию и все другие объявления с тем же именем, которые могут появиться в окружающих областях видимости:

struct s { int a; };
struct s; // does nothing (s already defined in this scope)
 
void g()
{
    struct s; // forward declaration of a new, local struct "s"
              // this hides global struct s until the end of this block
 
    s* p; // pointer to local struct s
 
    struct s { char* p; }; // definitions of the local struct s
}

Обратите внимание, что новое имя класса также может быть введено спецификатором типа с уточнением, который появляется в качестве части другого объявления, но только если поиск имени не может найти ранее объявленный класс с тем же именем.

class U;
 
namespace ns
{
    class Y f(class T p); // declares function ns::f and declares ns::T and ns::Y
 
    class U f(); // U refers to ::U
 
    // can use pointers and references to T and Y
    Y* p;
    T* q;
}

Спецификация члена

Спецификация члена или тело определения класса — это заключённая в фигурные скобки последовательность любого количества из следующего:

1) Объявления членов формы
attr (необязательно) decl-specifier-seq (необязательно) member-declarator-list (необязательно) ;
attr - (с C++11) любое количество атрибутов
decl-specifier-seq - последовательность спецификаторов. Она необязательна только в объявлениях конструкторов, деструкторов и пользовательских функций преобразования типов преобразования
member-declarator-list - подобно init-declarator-list, но дополнительно допускает объявление битового поля, чистую спецификацию, и virt-specifier (override или final)(с C++11), и не допускает синтаксис прямого инициализации без списка.

Это объявление может объявлять статические и нестатические члены данных и члены-функции, typedef членов, перечисления членов и вложенные классы. Это также может быть объявление друга.

class S
{
    int d1;             // non-static data member
    int a[10] = {1, 2}; // non-static data member with initializer (C++11)
 
    static const int d2 = 1; // static data member with initializer
 
    virtual void f1(int) = 0; // pure virtual member function
 
    std::string d3, *d4, f2(int); // two data members and a member function
 
    enum { NORTH, SOUTH, EAST, WEST };
 
    struct NestedS
    {
        std::string s;
    } d5, *d6;
 
    typedef NestedS value_type, *pointer_type;
};
2) Определения функций, которые одновременно объявляют и определяют члены-функции или функции-друга. Точка с запятой после определения члена-функции необязательна. Все функции, определённые внутри тела класса, автоматически встраиваются, если они не прикреплены к именному модулю(с C++20).
class M
{
    std::size_t C;
    std::vector<int> data;
public:
    M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // constructor definition
 
    int operator()(std::size_t r, std::size_t c) const // member function definition
    {
        return data[r * C + c];
    }
 
    int& operator()(std::size_t r, std::size_t c) // another member function definition
    {
        return data[r * C + c];
    }
};
3) Спецификаторы доступа public:, protected:, и private:
class S
{
public:
    S();          // public constructor
    S(const S&);  // public copy constructor
    virtual ~S(); // public virtual destructor
private:
    int* ptr; // private data member
};
4) Объявления using:
class Base
{
protected:
    int d;
};
 
class Derived : public Base
{
public:
    using Base::d;    // make Base's protected member d a public member of Derived
    using Base::Base; // inherit all bases' constructors (C++11)
};
5) Объявления static_assert:
template<typename T>
struct Foo
{
    static_assert(std::is_floating_point<T>::value, "Foo<T>: T must be floating point");
};
6) Объявления шаблонов членов членов:
struct S
{
    template<typename T>
    void f(T&& n);
 
    template<class CharT>
    struct NestedS
    {
        std::basic_string<CharT> s;
    };
};
7) Объявления псевдонимов типов псевдонимов:
template<typename T>
struct identity
{
    using type = T;
};
(с C++11)
8) Правила вывода шаблонов вложенных классов:
struct S
{
    template<class CharT>
    struct NestedS
    {
        std::basic_string<CharT> s;
    };
 
    template<class CharT>
    NestedS(std::basic_string<CharT>) -> NestedS<CharT>;
};
(с C++17)
9) Объявления using-enum:
enum class color { red, orange, yellow };
 
struct highlight
{
    using enum color;
};
(с C++20)

Локальные классы

Объявление класса может появиться внутри тела функции, в этом случае оно определяет локальный класс. Имя такого класса существует только в области видимости функции и недоступно снаружи.

  • У локального класса не может быть статических членов данных.
  • Члены-функции локального класса не имеют связей.
  • Члены-функции локального класса должны быть определены полностью внутри тела класса.
  • Локальные классы кроме типов лямбда-выражений(с C++14) не могут иметь шаблонов членов.
  • Локальные классы не могут иметь шаблонов-друзей.
  • Локальные классы не могут определять функции-друга внутри определения класса.
  • Локальный класс внутри функции (включая член-функцию) может получить доступ к тем же именам, что и окружающая функция.
  • Локальные классы не могли использоваться как аргументы шаблонов.
(до C++11)
#include <algorithm>
#include <iostream>
#include <vector>
 
int main()
{
    std::vector<int> v{1, 2, 3};
 
    struct Local
    {
        bool operator()(int n, int m)
        {
            return n > m;
        }
    };
 
    std::sort(v.begin(), v.end(), Local()); // since C++11
 
    for (int n : v)
        std::cout << n << ' ';
    std::cout << '\n';
}

Вывод:

3 2 1

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применено к Поведение при публикации Корректное поведение
CWG 1693 C++98 члены объявления не могли быть пустыми разрешено пустое объявление
CWG 1930 C++98 список-деклараторов-членов мог быть пустым, когда последовательность-спецификаторов-деклараций
содержала спецификатор класса хранения или квалификатор cv
список не должен быть пустым

См. также

Документация C для Struct declaration

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/class

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API