Spec-Zone.ru › C++

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

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

Синтаксис

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

class-key attr (optional) class-head-name final(optional) base-clause (optional) { member-specification } (1)
class-key attr (optional) base-clause (optional) { 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 (optional) decl-specifier-seq (optional) member-declarator-list (optional) ;
attr - (начиная с C++11) любое количество атрибутов
decl-specifier-seq - последовательность спецификаторов. Она может отсутствовать только в объявлениях конструкторов, деструкторов и определённых пользователем функций преобразования типов
member-declarator-list - аналогичен init-declarator-list, но дополнительно допускает объявление битового поля, pure-specifier и virt-specifier (override или final)(начиная с C++11), но не допускает синтаксис прямой инициализации без списка.

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

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) Определения функций, которые одновременно объявляют и определяют функции-члены или функции friend. Точка с запятой после определения функции-члена необязательна. Все функции, определённые внутри тела класса, автоматически являются встраиваемыми, если только они не связаны с именованным модулем(начиная с 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) не могут иметь шаблоны-члены.
  • Локальные классы не могут иметь шаблоны friend.
  • Локальные классы не могут определять функции friend внутри определения класса.
  • Локальный класс внутри функции (включая функцию-член) может обращаться к тем же именам, что и охватывающая его функция.
  • Локальные классы нельзя было использовать в качестве аргументов шаблона.
(до 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

Ключевые слова

class, struct, union

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

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

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

См. также

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

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

Spec-Zone.ru

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