Пространства имён
Варианты
Действия

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

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

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

Содержание

[править]Синтаксис

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

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

[править]Предварительное объявление

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

ключевое-слово-классаатрибутыидентификатор;

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

class Vector;// предварительное объявление   class Matrix {// ...friend Vector operator*(const Matrix&, const Vector&);};   class Vector {// ...friend Vector operator*(const Matrix&, const Vector&);};

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

// в MyStruct.h #include <iosfwd> // содержит предварительное объявление std::ostream   struct MyStruct {int value;friendstd::ostream& operator<<(std::ostream& os, const S& s);// определение предоставлено в файле MyStruct.cpp, который использует// #include <ostream>};

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

struct s {int a;};struct s;// ничего не делает (s уже определена в этой области видимости)   void g(){struct s;// предварительное объявление новой локальной структуры "s"// скрывает глобальные структуры до конца этого блока видимости   s* p;// указатель на локальную структуру s   struct s {char* p;};// определения локальной структуры s}

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

class U;   namespace ns {class Y f(class T p);// объявляет функцию ns::f и объявляет ns::T и ns::Y   class U f();// U ссылается на ::U   // можно использовать указатели и ссылки на T и Y Y* p; T* q;}

[править]Спецификация элемента

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

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

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

class S {int d1;// нестатический элемент данныхint a[10]={1,2};// нестатический элемент данных с инициализатором (C++11)   staticconstint d2 =1;// статический элемент данных с инициализатором   virtualvoid f1(int)=0;// чистая виртуальная функция-элемент   std::string d3, *d4, f2(int);// два элемента данных и функция-элемент   enum{NORTH, SOUTH, EAST, WEST};   struct NestedS {std::string s;} d5, *d6;   typedef NestedS value_type, *pointer_type;};
2) Определения функций, которые объявляют и определяют функции-элементы или дружественные функции. Точка с запятой после определения функции-элемента необязательна. Все функции, определённые внутри тела класса, автоматически становятся inline, если только они не присоединены к именованному модулю(начиная с 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){}// определение конструктора   int operator()(std::size_t r, std::size_t c)const// определение функции-элемента{return data[r * C + c];}   int& operator()(std::size_t r, std::size_t c)// другое определение функции-элемента{return data[r * C + c];}};
3)Спецификаторы доступаpublic:, protected: и private:
class S {public: S();// открытый конструктор S(const S&);// открытый конструктор копированияvirtual ~S();// открытый виртуальный деструкторprivate:int* ptr;// закрытый элемент данных};
4)Using-объявления:
class Base {protected:int d;};   class Derived :public Base {public:using Base::d;// делает защищённый элемент базового класса d// открытым элементом производногоusing Base::Base;// наследует конструкторы всех базовых классов (C++11)};
5) Объявление static_assert:
template<typename T>struct Foo { static_assert(std::is_floating_point<T>::value, "Foo<T>: T должен быть с"" плавающей запятой");};
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:
enumclass color { red, orange, yellow };   struct highlight {usingenum color;};
(начиная с C++20)

[править]Локальные классы

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

  • Локальный класс не может иметь статических элементов данных
  • Функции-элементы локального класса не имеют связывания
  • Функции-элементы локального класса должны быть определены полностью внутри тела класса
  • Локальные классы , отличные от типов замыкания,(начиная с C++14) не могут иметь шаблонных элементов
  • Локальные классы не могут иметь дружественные шаблоны
  • Локальные классы не могут определять дружественные функции внутри определения класса
  • Локальный класс внутри функции (включая функцию-элемент) может обращаться к тем же именам, к которым может обращаться включающая функция.
  • локальные классы нельзя было использовать в качестве аргументов шаблона
(до C++11)
#include <vector>#include <algorithm>#include <iostream>   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());// начиная с C++11   for(int n : v)std::cout<< n <<' ';}

Вывод:

3 2 1

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

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

[править]Смотрите также

Документация C по Объявление структуры
close