12 Classes [class]

Класс - это тип. Его имя становится class-name([class.name]) внутри его области видимости.

class-name:
	identifier
	simple-template-id

Class-specifiers и elaborated-type-specifiers используются для изготовления class-names. Объект класса состоит из (возможно, пустой) последовательности членов и объектов базового класса.

class-specifier:
	class-head { member-specificationopt }
class-head:
	class-key attribute-specifier-seqopt class-head-name class-virt-specifieropt base-clauseopt
	class-key attribute-specifier-seqopt base-clauseopt
class-head-name:
	nested-name-specifieropt class-name
class-virt-specifier:
	final
class-key:
	class
	struct
	union

A class-specifier, в котором class-headотсутствует, class-head-nameопределяет безымянный класс. [ Note: Таким образом, безымянный класс быть не может final. ] end note

A class-nameвставляется в область видимости, в которой он объявлен, сразу после того, class-nameкак виден. class-nameТакже вставляется в сферу самого класса; это известно как injected-class-name. В целях проверки доступа имя внедренного класса обрабатывается так, как если бы оно было публичным именем члена. A class-specifierобычно называют определением класса. Класс считается определенным после того, как его закрывающая скобка class-specifierбыла замечена, даже если его функции-члены, как правило, еще не определены. Необязательный attribute-specifier-seqэлемент принадлежит классу; атрибуты в attribute-specifier-seqвпоследствии считаются атрибутами класса, когда бы он ни был назван.

Если класс отмечен значком class-virt-specifier final и отображается как значок class-or-decltypea base-clause, программа сформирована неправильно. Когда за a class-keyследует a class-head-name, то identifier finalи двоеточие или левая фигурная скобка final интерпретируются как a class-virt-specifier. [Example:

struct A;
struct A final {};      // OK: definition of struct A,
                        // not value-initialization of variable final

struct X {
 struct C { constexpr operator int() { return 5; } };
 struct B final : C{};  // OK: definition of nested class B,
                        // not declaration of a bit-field member final
};

end example]

Полные объекты и подобъекты-члены типа класса должны иметь ненулевой размер.107 [ Note: Объекты классов могут быть назначены, переданы в качестве аргументов функциям и возвращены функциями (за исключением объектов классов, для которых копирование или перемещение было ограничено; см. [class.copy]). Другие правдоподобные операторы, такие как сравнение на равенство, могут быть определены пользователем; см [over.oper]. ]end note

A union - это класс, определенный с помощью class-key union; одновременно он содержит не более одного элемента данных ([class.union]). [ Note: Агрегаты типа класса описаны в [dcl.init.aggr]. ]end note

А trivially copyable class - это класс:

  • где каждый конструктор копирования, конструктор перемещения, оператор присваивания копии и оператор присваивания перемещения ([class.copy], [over.ass]) либо удаляются, либо тривиальны,

  • который имеет хотя бы один не удаленный конструктор копии, конструктор перемещения, оператор присваивания копии или оператор присваивания перемещения, и

  • который имеет тривиальный, не удаленный destructor.

A trivial class - это класс, который легко копируется и имеет один или несколько default constructors, все из которых либо тривиальны, либо удалены, и по крайней мере один из них не удален. [ Note: В частности, тривиально копируемый или тривиальный класс не имеет виртуальных функций или виртуальных базовых классов. ]end note

Класс S - это standard-layout class если он:

  • не имеет нестатических элементов данных типа нестандартного класса макета (или массива таких типов) или ссылки,

  • нет virtual functions и нет virtual base classes,

  • имеет то же самое access control для всех нестатических членов данных,

  • не имеет базовых классов нестандартной компоновки,

  • имеет не более одного подобъекта базового класса любого заданного типа,

  • имеет все нестатические элементы данных и битовые поля в классе и его базовых классах, впервые объявленных в том же классе, и

  • не имеет элемента набора M(S) типов (определенного ниже) в качестве базового класса.108

M(X) определяется следующим образом:

  • Если X это тип класса без объединения и без (возможно inherited) нестатических элементов данных, набор M(X) будет пустым.

  • Если X это тип класса без объединения, первый нестатический член данных которого имеет тип X0 (где указанный член может быть анонимным объединением), набор M(X) состоит из X0 элементов и элементов M(X0).

  • Если X это тип объединения, набор M(X) является объединением всех M(Ui) и набора, содержащего все Ui, где каждый Ui является типом ith нестатического члена данных X.

  • Если X это тип массива с типом элемента Xe, набор M(X) состоит из Xe элементов и M(Xe).

  • Если X это неклассовый тип, не являющийся массивом, набор M(X) будет пустым.

[ Note: M(X) - это набор типов всех подобъектов не базового класса, для которых в классе стандартной компоновки гарантировано нулевое смещение в X. ] end note

[Example:

   struct B { int i; };         // standard-layout class
   struct C : B { };            // standard-layout class
   struct D : C { };            // standard-layout class
   struct E : D { char : 4; };  // not a standard-layout class

   struct Q {};
   struct S : Q { };
   struct T : Q { };
   struct U : S, T { };         // not a standard-layout class

end example]

A standard-layout struct - это класс стандартной компоновки, определенный с помощью class-key struct или class-key class. A standard-layout union - это класс стандартного макета, определенный с помощью class-key union.

[ Note: Классы стандартной компоновки полезны для взаимодействия с кодом, написанным на других языках программирования. Их расположение указано в [class.mem]. ]end note

A POD struct109 - это класс без объединения, который является одновременно тривиальным классом и классом стандартного макета и не имеет нестатических элементов данных типа, отличного от структуры POD, объединения без POD (или массива таких типов). Точно так же a POD union - это объединение, которое является как тривиальным классом, так и классом стандартного макета, и не имеет нестатических элементов данных типа, отличного от структуры POD, объединения без POD (или массива таких типов). A POD class - это класс, который является либо структурой POD, либо объединением POD.

[Example:

struct N {          // neither trivial nor standard-layout
  int i;
  int j;
  virtual ~N();
};

struct T {          // trivial but not standard-layout
  int i;
private:
  int j;
};

struct SL {         // standard-layout but not trivial
  int i;
  int j;
  ~SL();
};

struct POD {        // both trivial and standard-layout
  int i;
  int j;
};

end example]

Если a class-head-nameсодержит a nested-name-specifier, то class-specifierдолжен ссылаться на класс, который был ранее объявлен непосредственно в классе или пространстве имен, на которое nested-name-specifierссылается, или в элементе inline namespace set этого пространства имен (т. Е. Не просто унаследован или введен a using-declaration), и class-specifierдолжен появляются в пространстве имен, включающем предыдущее объявление. В таких случаях nested-name-specifierиз class-head-nameопределения не должно начинаться с decltype-specifier.

Подобъекты базового класса не так ограничены.

Это гарантирует, что два подобъекта, которые имеют один и тот же тип класса и принадлежат одному и тому же наиболее производному объекту, не будут размещены по одному и тому же адресу ([expr.eq]).

Аббревиатура POD означает «старые добрые данные».

12.1 Class names [class.name]

Определение класса вводит новый тип. [Example:

struct X { int a; };
struct Y { int a; };
X a1;
Y a2;
int a3;

объявляет три переменные трех разных типов. Это означает, что

a1 = a2;                        // error: Y assigned to X
a1 = a3;                        // error: int assigned to X

несоответствия типов, и что

int f(X);
int f(Y);

объявить overloaded функцию, f() а не просто одну функцию f() дважды. По той же причине,

struct S { int a; };
struct S { int a; };            // error, double definition

неправильно сформирован, потому что он определяет S дважды. ]end example

Объявление класса вводит имя класса в область, в которой оно объявлено, и скрывает любой класс, переменную, функцию или другое объявление с этим именем во вложении scope. Если имя класса объявлено в области, где также объявлены переменная, функция или перечислитель с тем же именем, тогда, когда оба объявления находятся в области видимости, на класс можно ссылаться только с помощью elaborated-type-specifier([basic.lookup.elab]). [Example:

struct stat {
  // ...
};

stat gstat;                     // use plain stat to define variable

int stat(struct stat*);         // redeclare stat as function

void f() {
  struct stat* ps;              // struct prefix needed to name struct stat
  stat(ps);                     // call stat()
}

end example] A, состоящий исключительно из, является либо повторным объявлением имени в текущей области, либо прямым объявлением идентификатора как имени класса. Он вводит имя класса в текущую область видимости. [declarationclass-key identifier; Example:

struct s { int a; };

void g() {
  struct s;                     // hide global struct s with a block-scope declaration
  s* p;                         // refer to local struct s
  struct s { char* p; };        // define local struct s
  struct s;                     // redeclaration, has no effect
}

end example] [ Note: Такие объявления позволяют определять классы, которые ссылаются друг на друга. [Example:

class Vector;

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

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

Объявление friends описано в [class.friend], операторные функции - в [over.oper]. ] ]end exampleend note

[ Note: An elaborated-type-specifierтакже может использоваться type-specifierкак часть объявления. Он отличается от объявления класса тем, что, если класс с подробным именем находится в области видимости, разработанное имя будет ссылаться на него. ] [end noteExample:

struct s { int a; };

void g(int s) {
  struct s* p = new struct s;   // global s
  p->a = s;                     // parameter s
}

end example]

[ Note: Объявление имени класса вступает в силу сразу после того, как identifierбудет замечено в определении класса или elaborated-type-specifier. Например,

class A * A;

first указывает, A что это имя класса, а затем переопределяет его как имя указателя на объект этого класса. Это означает, что class A для ссылки на класс необходимо использовать разработанную форму . Такой артистизм с именами может сбивать с толку, и его лучше избегать. ]end note

Имя typedef-nameтипа класса или его cv-квалифицированная версия также является class-name. Если a, typedef-nameкоторый именует тип класса cv-Qualified, используется там, где a class-nameтребуется, cv-квалификаторы игнорируются. А typedef-nameне должно использоваться как identifierв class-head.

12.2 Class members [class.mem]

member-specification:
	member-declaration member-specificationopt
	access-specifier : member-specificationopt
member-declaration:
	attribute-specifier-seqopt decl-specifier-seqopt member-declarator-listopt ;
	function-definition
	using-declaration
	static_assert-declaration
	template-declaration
	deduction-guide
	alias-declaration
	empty-declaration
member-declarator-list:
	member-declarator
	member-declarator-list , member-declarator
member-declarator:
	declarator virt-specifier-seqopt pure-specifieropt
	declarator brace-or-equal-initializeropt
	identifieropt attribute-specifier-seqopt : constant-expression
virt-specifier-seq:
	virt-specifier
	virt-specifier-seq virt-specifier
virt-specifier:
	override
	final
pure-specifier:
	= 0

В member-specificationопределении класса объявляется полный набор членов класса; ни один участник не может быть добавлен в другое место. A direct member класса X - это член, X который был впервые объявлен внутри member-specificationкласса X, включая анонимные объекты объединения ([class.union.anon]) и их прямые члены. Члены класса - это члены данных member functions, вложенные типы, перечислители member templates и их специализации. [ Note: Специализацией шаблона статического элемента данных является статический член данных. Специализацией шаблона функции-члена является функция-член. Специализацией шаблона класса-члена является вложенный класс. ]end note

A member-declarationне объявляет новых членов класса, если он

Для любого другого member-declarationкаждый объявленный объект, который не является, unnamed bit-field является членом класса, и каждый такой member-declaration должен либо объявить по крайней мере одно имя члена класса, либо объявить по крайней мере одно безымянное битовое поле.

A data member - нефункциональный член, представленный a member-declarator. A member function - это член, являющийся функцией. Вложенные типы - это классы ([class.name], [class.nest]), enumerations объявленные в классе, и произвольные типы, объявленные как члены с помощью символа typedef declaration или alias-declaration. Перечислители unscoped enumeration определенного в классе являются членами класса.

Член данных или функция - член может быть объявлена static в его member-declaration, в этом случае он является static member (см [class.static]) (а static data member ([class.static.data]) или static member function ([class.static.mfct]) соответственно) класса. Любой другой член данных или функция-член - это non-static member (a non-static data member или non-static member function ([class.mfct.non-static]) соответственно). [ Note: Нестатический член данных не ссылочного типа является подобъектом члена объекта класса ([intro.object]). ]end note

Член не может быть объявлен дважды в группе member-specification, за исключением того, что

  • шаблон вложенного класса или класса-члена может быть объявлен, а затем определен позже, и

  • перечисление можно ввести с помощью, opaque-enum-declarationа затем повторно объявить с помощью enum-specifier.

[ Note: Одно имя может обозначать несколько функций-членов при условии, что их типы существенно различаются (пункт [over]). ]end note

Класс считается полностью определенным типом объекта ([basic.types]) (или полный типом) , при закрытии } из class-specifier. Внутри класса member-specificationкласс считается завершенным в телах функций, аргументах по noexcept-specifiersумолчанию и инициализаторах членов по умолчанию (включая такие вещи во вложенных классах). В противном случае он считается неполным в рамках своего класса member-specification.

В a member-declarator, = следующий за declarator ним интерпретируется как вводящий, pure-specifier если у declarator-idнего есть тип функции, в противном случае он интерпретируется как вводящий brace-or-equal-initializer. [Example:

struct S {
  using T = void();
  T * p = 0;        // OK: brace-or-equal-initializer
  virtual T f = 0;  // OK: pure-specifier
};

end example]

A brace-or-equal-initializerдолжен появляться только в объявлении элемента данных. (Для статических элементов данных см [class.static.data].; Для нестатических элементов данных см. [class.base.init] И [dcl.init.aggr]). A brace-or-equal-initializerдля нестатического члена данных указывает a default member initializer для члена и не должен прямо или косвенно вызывать неявное определение конструктора по умолчанию по умолчанию для включающего класса или спецификации исключения этого конструктора.

Член не может быть объявлен с . В определении класса член не должен объявляться с помощью, если он также не объявлен . extern storage-class-specifier thread_­local storage-class-specifier static

decl-specifier-seqМожет быть опущен только в деклараций конструктор, деструктор и функция преобразования; при объявлении другого типа члена в нем decl-specifier-seq должен содержаться a, type-specifierкоторый не является a cv-qualifier. member-declarator-listМожет быть опущен только после того, как class-specifierили enum-specifierили в friend declaration. A pure-specifierдолжен использоваться только в декларации a, virtual function которая не является friend декларацией.

Необязательный параметр attribute-specifier-seqв a member-declaration относится к каждой из сущностей, объявленных объектом member-declarators; он не должен появляться, если member-declarator-listопущено необязательное .

A virt-specifier-seqдолжен содержать не более одного каждого из них virt-specifier. А virt-specifier-seq должен фигурировать только в декларации а virtual member function.

Нестатические элементы данных не должны иметь неполных типов. В частности, класс C не должен содержать нестатического члена класса C, но он может содержать указатель или ссылку на объект класса C.

[ Note: См. [expr.prim] Ограничения на использование нестатических элементов данных и нестатических функций-членов. ]end note

[ Note: Тип нестатической функции-члена - это обычный тип функции, а тип нестатического члена данных - это обычный тип объекта. Не существует специальных типов функций-членов или типов данных-членов. ]end note

[ Example: Простой пример определения класса:

struct tnode {
  char tword[20];
  int count;
  tnode* left;
  tnode* right;
};

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

tnode s, *sp;

объявляет s как tnode и sp как указатель на tnode. С помощью этих объявлений sp->count относится к count члену объекта, на который sp указывает; s.left ссылается на left указатель поддерева объекта s; и s.right->tword[0] относится к начальному символу tword члена right поддерева s. ]end example

Нестатические элементы данных класса (не объединенного) с тем же самым access control выделяются так, чтобы более поздние члены имели более высокие адреса в объекте класса. Порядок распределения нестатических членов данных с разными access control не определен. Требования согласования реализации могут привести к тому, что два соседних элемента не будут размещены сразу после друг друга; так что требования к пространству для управления virtual functions и виртуального base classes.

Если T это имя класса, то каждое из следующих имен должно иметь имя, отличное от T:

  • каждый статический член данных класса T;

  • каждая функция-член класса T [ Note: Это ограничение не распространяется на те constructors, у которых нет имен ];end note

  • каждый член класса, T который сам является типом;

  • каждый шаблон члена класса T;

  • каждый перечислитель каждого члена класса, T который является перечислимым типом без области действия; а также

  • каждый член каждого анонимного союза, который является членом класса T.

Кроме того, если класс T объявлен пользователем constructor, каждый нестатический член данных класса T должен иметь имя, отличное от T.

common initial sequence Двух standard-layout struct типов является самой длинной последовательности нестатические элементов данных и битовых полей в порядке декларации, начиная с первого такого лица в каждой из структур, таким образом, что соответствующие лица имеют макет-совместимых типов и либо ни юридическое лицо немного -field или оба являются битовыми полями с одинаковой шириной. [Example:

  struct A { int a; char b; };
  struct B { const int b1; volatile char b2; };
  struct C { int c; unsigned : 0; char b; };
  struct D { int d; char b : 4; };
  struct E { unsigned int e; char b; };

Общая начальная последовательность A и B включает всех членов любого класса. Общая начальная последовательность A and C и of A и D включает в себя первый член в каждом случае. Общая начальная последовательность A и E пуста. ]end example

Два standard-layout struct типа - это layout-compatible classes если их общая начальная последовательность включает все члены и битовые поля обоих классов ([basic.types]).

Два объединения со стандартным макетом совместимы с макетом, если они имеют одинаковое количество нестатических элементов данных и соответствующие нестатические элементы данных (в любом порядке) layout-compatible types.

В объединении стандартного макета с active member типом структуры T1разрешено читать нестатический член m данных другого члена объединения с типом структуры, T2 если он m является частью общей начальной последовательности T1 и T2; поведение такое, как если бы был назначен член-корреспондент T1 . [Example:

struct T1 { int a, b; };
struct T2 { int c; double d; };
union U { T1 t1; T2 t2; };
int f() {
  U u = { { 1, 2 } };   // active member is t1
  return u.t2.c;        // OK, as if u.t1.a were nominated
}

end example] [ Note: Чтение изменчивого объекта через энергонезависимое значение glvalue имеет неопределенное поведение ([dcl.type.cv]). ]end note

Если объект класса стандартного макета имеет какие-либо нестатические элементы данных, его адрес совпадает с адресом его первого нестатического члена данных. В противном случае его адрес совпадает с адресом его первого подобъекта базового класса (если есть). [ Note: Следовательно, внутри объекта структуры стандартного макета может быть безымянное заполнение, но не в его начале, что необходимо для достижения надлежащего выравнивания. ] [ Объект и его первый подобъект взаимопреобразуемы по указателю ( , ). ]end noteNote: [basic.compound] [expr.static.cast]end note

12.2.1 Member functions [class.mfct]

Функция-член может быть defined в своем определении класса, и в этом случае это inline функция-член, или она может быть определена вне определения своего класса, если она уже была объявлена, но не определена в определении своего класса. Определение функции-члена, которое появляется за пределами определения класса, должно появиться в области пространства имен, включающей определение класса. За исключением определений функций-членов, которые появляются вне определения класса, и за исключением явных специализаций функций-членов шаблонов классов и шаблонов функций-членов ([temp.spec]), появляющихся вне определения класса, функция-член не должна повторно объявляться.

Встроенная функция-член (статическая или нестатическая) также может быть определена вне ее определения класса, если ее объявление в определении класса или ее определение вне определения класса объявляет функцию как inline или constexpr. [ Note: Функции-члены класса в области пространства имен имеют связь с этим классом. Функции- local class члены не связаны. Смотрите [basic.link]. ]end note

[ Note: В программе может быть не более одного определения не встроенной функции-члена. В программе может быть несколько inline определений функции-члена. Смотрите [basic.def.odr] и [dcl.inline]. ]end note

Если определение функции-члена лексически находится за пределами определения ее класса, имя функции-члена должно быть уточнено именем ее класса с использованием ​::​ оператора. [ Note: Имя, используемое в определении функции-члена (то есть при parameter-declaration-clauseвключении default arguments или в теле функции-члена) ищется, как описано в [basic.lookup]. ] [end noteExample:

struct X {
  typedef int T;
  static T count;
  void f(T);
};
void X::f(T t = count) { }

Функция-член f класса X определяется в глобальной области видимости; обозначение X​::​f указывает, что функция f является членом класса X и находится в области действия класса X. В определении функции тип параметра T относится к члену typedef, T объявленному в классе, X а аргумент по умолчанию count относится к статическому члену данных, count объявленному в классе X. ]end example

[ Локальные переменный или локальный типа в функции члена всегда относится к той же сущности, или нет функции члена . ]Note: static inlineend note

В объявлениях могут упоминаться ранее объявленные функции-члены friend .

Функции-члены локального класса должны быть определены встроенными в определение их класса, если они вообще определены.

[ Note: Функция-член может быть объявлена ​​(но не определена) с использованием typedef для типа функции. Результирующая функция-член имеет точно такой же тип, как если бы декларатор функции был указан явно, см [dcl.fct]. Например,

typedef void fv();
typedef void fvc() const;
struct S {
  fv memfunc1;      // equivalent to: void memfunc1();
  void memfunc2();
  fvc memfunc3;     // equivalent to: void memfunc3() const;
};
fv  S::* pmfv1 = &S::memfunc1;
fv  S::* pmfv2 = &S::memfunc2;
fvc S::* pmfv3 = &S::memfunc3;

Также см [temp.arg]. ]end note

12.2.2 Non-static member functions [class.mfct.non-static]

Нестатическая функция-член может быть вызвана для объекта своего типа класса или для объекта класса derived из его типа класса с использованием class member access синтаксиса ([over.match.call]). Нестатическая функция-член также может быть вызвана напрямую с использованием синтаксиса вызова функции ([expr.call], [over.match.call]) из тела функции-члена своего класса или класса, производного от этого класса.

Если нестатическая функция-член класса X вызывается для объекта, не относящегося к типу Xили производному от него X, поведение не определено.

Когда объект, id-expressionкоторый не является частью class member access синтаксиса и не используется для формирования указателя на member ([expr.unary.op]), используется в члене класса X в контексте, где this может использоваться, если name lookup разрешает имя в id-expressionнестатическом члене, не являющемся типом некоторого класса C, и если либо id-expressionпотенциально оценивается, либо C является X базовым классом X, то id-expressionпреобразуется в class member access выражение, использующее (*this) в postfix-expression качестве слева от . оператора. [ Note: Если C не X является базовым классом или Xявляется некорректным выражением доступа к члену класса. ] Аналогично во время поиска имени, когда используемый в определении функции-члена для класса разрешается в статический член, перечислитель или вложенный тип класса или базового класса , преобразуется в, в котором имена класса функции-члена. Эти преобразования не применяются в контексте определения шаблона ( ). [end noteunqualified-id X X Xunqualified-idqualified-idnested-name-specifier[temp.dep.type]Example:

struct tnode {
  char tword[20];
  int count;
  tnode* left;
  tnode* right;
  void set(const char*, tnode* l, tnode* r);
};

void tnode::set(const char* w, tnode* l, tnode* r) {
  count = strlen(w)+1;
  if (sizeof(tword)<=count)
      perror("tnode string too long");
  strcpy(tword,w);
  left = l;
  right = r;
}

void f(tnode n1, tnode n2) {
  n1.set("abc",&n2,0);
  n2.set("def",0,0);
}

В теле функции члена tnode​::​set, имена членов tword, count, leftи right обратиться к членам объекта , для которого эта функция вызывается. Таким образом, в вызове n1.set("abc",&n2,0), tword относится к n1.tword, а в вызове n2.set("def",0,0), он относится к n2.tword. Функции strlen, perrorи strcpy не являются членами класса tnode и должны быть объявлены в другом месте. ]110 end example

Функция - член нестатический может быть объявлена const, volatileили const volatile. Это cv-qualifiers влияет на тип файла this pointer. Они также влияют function type на функцию-член; функция - член объявлена const является const функция, функция - член объявлена volatile является volatile функцией членом и функция объявлена членом const volatile является const volatile функцией - членом. [Example:

struct X {
  void g() const;
  void h() const volatile;
};

X​::​g является const функцией членом и X​::​h является const volatile функцией - членом. ]end example

Нестатическая функция-член может быть объявлена ​​с помощью ref-qualifier([dcl.fct]); см [over.match.funcs].

Нестатическая функция-член может быть объявлена virtual ([class.virtual]) или pure virtual ([class.abstract]).

См., Например, <cstring> ([c.strings]).

12.2.2.1 The this pointer [class.this]

В теле нестатического member functionключевого слова ключевое слово this представляет собой выражение prvalue, значение которого является адресом объекта, для которого вызывается функция. Типа this в функции - члене класса X есть X*. Если функция-член объявлена const, типом this является const X*, если функция-член объявлена volatile, типом this является volatile X*, а если функция-член объявлена const volatile, типом this является const volatile X*. [ Note: Таким образом, в const функции-члене доступ к объекту, для которого вызывается функция, осуществляется через const путь доступа. ] [ end noteExample:

struct s {
  int a;
  int f() const;
  int g() { return a++; }
  int h() const { return a++; } // error
};

int s::f() const { return a; }

В a++ теле s​::​h неправильно сформирован, потому что он пытается изменить (часть) объекта, для которого s​::​h() вызывается. Это недопустимо в const функции-члене, потому что this это указатель на const; то есть *this имеет const тип. ]end example

Аналогичным образом volatile семантика применяется в volatile функциях-членах при доступе к объекту и его нестатическим элементам данных.

Функция-член с квалификацией cv может быть вызвана object-expression только в том случае, если объект-выражение имеет квалификацию cv или менее квалификацию cv, чем функция-член. [Example:

void k(s& x, const s& y) {
  x.f();
  x.g();
  y.f();
  y.g();                        // error
}

Вызов y.g() плохо сформирован, потому что y является const и s​::​g() являетсяconst функцией, не являющейся членом, то s​::​g() есть менее квалифицированной, чем объект-выражение y. ]end example

Constructors и destructors не объявляются const, volatile или const volatile. [ Note: Тем не менее, эти функции могут быть вызваны для создания и уничтожения объектов с Cv квалифицированных типов см [class.ctor] и [class.dtor]. ]end note

12.2.3 Static members [class.static]

На статический член s класса X можно ссылаться с помощью qualified-idвыражения X​::​s; нет необходимости использовать class member access синтаксис для ссылки на статический член. На статический член можно ссылаться с использованием синтаксиса доступа к члену класса, и в этом случае вычисляется выражение объекта. [Example:

struct process {
  static void reschedule();
};
process& g();

void f() {
  process::reschedule();        // OK: no object necessary
  g().reschedule();             // g() is called
}

end example]

На статический член можно ссылаться непосредственно в области его класса или в области действия класса derived из своего класса; В этом случае статический член упоминаются как если qualified-idиспользовалось выражение, с nested-name-specifierиз qualified-idимен в области видимости класса , из которого ссылается статический член. [Example:

int g();
struct X {
  static int g();
};
struct Y : X {
  static int i;
};
int Y::i = g();                 // equivalent to Y​::​g();

end example]

Если unqualified-idиспользуется в определении статического члена, следующего за членом declarator-id, и name lookup обнаруживается, что это unqualified-idотносится к статическому члену, перечислителю или вложенному типу класса члена (или базового класса класса члена), то unqualified-idпреобразуется в qualified-idвыражение , в котором nested-name-specifierимена класс сферы применения , из которого ссылается элемент. [ Note: См. [expr.prim] Ограничения на использование нестатических элементов данных и нестатических функций-членов. ]end note

Статические члены подчиняются обычному классу member access rules. При использовании в объявлении члена класса static спецификатор должен использоваться только в объявлениях члена, которые появляются внутри member-specificationопределения класса. [ Note: Его нельзя указывать в объявлениях членов, которые появляются в области пространства имен. ]end note

12.2.3.1 Static member functions [class.static.mfct]

[ Note: Правила, описанные в [class.mfct] разделе, применяются к статическим функциям-членам. ]end note

[ Note: Статическая функция-член не имеет this pointer. ] Статической функции-члена быть не должно . Не должно быть статической и нестатической функции-члена с одним и тем же именем и одними и теми же типами параметров ( ). Функция - член статический не должен быть объявлен , или .end note virtual[over.load] constvolatile const volatile

12.2.3.2 Static data members [class.static.data]

Статический член данных не является частью подобъектов класса. Если объявлен статический член данных, thread_­local существует одна копия члена на поток. Если статический член данных не объявлен, thread_­local существует одна копия члена данных, совместно используемая всеми объектами класса.

Объявление не встроенного статического члена данных в определении его класса не является определением и может иметь неполный тип, отличный от cv void. Определение статического члена данных, который не определен встроенным в определение класса, должно появиться в области пространства имен, включающей определение класса члена. В определении в области пространства имен имя статического элемента данных должно быть уточнено именем его класса с использованием ​::​ оператора. initializerВыражение в определении члена статических данных в рамках своего класса ([basic.scope.class]). [Example:

class process {
  static process* run_chain;
  static process* running;
};

process* process::running = get_main();
process* process::run_chain = running;

Статический член run_­chain данных класса process определяется в глобальной области видимости; обозначение process​::​run_­chain указывает, что член run_­chain является членом класса process и находится в области действия класса process. В определении статического члена данных initializerвыражение относится к статическому члену running данных класса process. ]end example

[ Note: После определения статического элемента данных он существует, даже если объекты его класса не были созданы. [ Example: В приведенном выше примере run_­chain и running существуют, даже если программа не process создает никаких объектов класса . ] ]end exampleend note

Если энергонезависимый не встроенный const статический член данных имеет целочисленный или перечисляемый тип, его объявление в определении класса может указывать a, brace-or-equal-initializerв котором каждый, initializer-clauseкоторый является, assignment-expression является постоянным выражением ([expr.const]). Этот член по-прежнему должен быть определен в области пространства имен, если он находится odr-used в программе, а определение области пространства имен не должно содержать initializer. Встроенный статический член данных может быть определен в определении класса и может указывать brace-or-equal-initializer. Если член объявлен со constexpr спецификатором, он может быть повторно объявлен в области пространства имен без инициализатора (это использование не рекомендуется; см. [depr.static_constexpr]). Объявления других статических элементов данных не должны указывать a brace-or-equal-initializer.

[ Note: В программе должно быть ровно одно определение статического элемента данных odr-used ; Диагностика не требуется. ] Безымянные классы и классы, прямо или косвенно содержащиеся в безымянных классах, не должны содержать статических элементов данных.end note

[ Note: Статические элементы данных класса в области пространства имен имеют значение linkage этого класса. A local class не может иметь статических элементов данных. ]end note

Статические элементы данных инициализируются и уничтожены точно так же как нелокальных переменных ([basic.start.static], [basic.start.dynamic], [basic.start.term]).

Статический член данных быть не может mutable.

12.2.4 Bit-fields [class.bit]

А member-declaratorформы

identifieropt  attribute-specifier-seqopt : constant-expression

указывает битовое поле; его длина отделяется от имени битового поля двоеточием. Необязательный параметр attribute-specifier-seqотносится к объявляемой сущности. Атрибут битового поля не является частью типа члена класса. constant-expressionДолжна быть интегральным выражением постоянная с большим значением , чем или равно нуль. Значение выражения интегральной константы может быть больше, чем количество бит в object representation типе битового поля; в таких случаях дополнительные биты используются как биты заполнения и не участвуют в value representation битовом поле. Размещение битовых полей внутри объекта класса определяется реализацией. Выравнивание битовых полей определяется реализацией. Битовые поля упакованы в некоторую адресуемую единицу распределения. [ Note: Битовые поля охватывают единицы распределения на одних машинах, но не на других. Битовые поля назначаются справа налево на одних машинах, слева направо на других. ]end note

Объявление для битового поля, в котором не identifier объявляется unnamed bit-field. Безымянные битовые поля не являются членами и не могут быть инициализированы. [ Note: Безымянное битовое поле полезно для заполнения, чтобы соответствовать внешним макетам. ] В качестве особого случая безымянное битовое поле с нулевой шириной определяет выравнивание следующего битового поля на границе единицы распределения. Только при объявлении безымянного битового поля значение поля может быть равно нулю.end noteconstant-expression

Битовое поле не должно быть статическим членом. Битовое поле должно иметь целочисленный или перечислительный тип ([basic.fundamental]). Значение может успешно быть сохранены в битовое поле любого размера ненулевой. Оператор адресации не должен применяться к битовому полю, поэтому нет указателей на битовые поля. Неконстантная ссылка не должна быть привязана к битовому полю ( ). [ Если инициализатором для ссылки типа является lvalue, которое относится к битовому полю, ссылка привязывается к временному инициализированному объекту для хранения значения битового поля; ссылка не связана напрямую с битовым полем. Смотрите . ] bool & [dcl.init.ref]Note: const T& [dcl.init.ref]end note

Если значение true или false сохраняется в битовом поле bool любого размера (включая однобитовое битовое поле), исходное bool значение и значение битового поля должны сравниваться как равные. Если значение перечислителя хранится в битовом поле того же типа перечисления, а количество битов в битовом поле достаточно велико, чтобы содержать все его значения enumeration type, исходное значение перечислителя и значение битового поля. поле сравнивать равно. [Example:

enum BOOL { FALSE=0, TRUE=1 };
struct A {
  BOOL b:1;
};
A a;
void f() {
  a.b = TRUE;
  if (a.b == TRUE)              // yields true
    { /* ... */ }
}

end example]

12.2.5 Nested class declarations [class.nest]

Класс может быть объявлен внутри другого класса. Класс, объявленный внутри другого, называется nested классом. Имя вложенного класса является локальным для включающего его класса. Вложенный класс находится в области его включающего класса. [ Note: См. [expr.prim] Ограничения на использование нестатических элементов данных и нестатических функций-членов. ]end note

[Example:

int x;
int y;

struct enclose {
  int x;
  static int s;

  struct inner {
    void f(int i) {
      int a = sizeof(x);        // OK: operand of sizeof is an unevaluated operand
      x = i;                    // error: assign to enclose​::​x
      s = i;                    // OK: assign to enclose​::​s
      ::x = i;                  // OK: assign to global x
      y = i;                    // OK: assign to global y
    }
    void g(enclose* p, int i) {
      p->x = i;                 // OK: assign to enclose​::​x
    }
  };
};

inner* p = 0;                   // error: inner not in scope

end example]

Функции-члены и статические элементы данных вложенного класса могут быть определены в области пространства имен, включающей определение их класса. [Example:

struct enclose {
  struct inner {
    static int x;
    void f(int i);
  };
};

int enclose::inner::x = 1;

void enclose::inner::f(int i) { /* ... */ }

end example]

Если класс X определен в области пространства имен, вложенный класс Y может быть объявлен в классе X и позже определен в определении класса X или позже определен в области пространства имен, включающей определение класса X. [Example:

class E {
  class I1;                     // forward declaration of nested class
  class I2;
  class I1 { };                 // definition of nested class
};
class E::I2 { };                // definition of nested class

end example]

Как и функция-член, friend function определенный внутри вложенного класса находится в лексической области видимости этого класса; он подчиняется тем же правилам привязки имен, static member function что и класс этого класса, но не имеет особых прав доступа к членам включающего класса.

12.2.6 Nested type names [class.nested.type]

Имена типов подчиняются точно таким же правилам области видимости, как и другие имена. В частности, имена типов, определенные в определении класса, не могут использоваться вне своего класса без уточнения. [Example:

struct X {
  typedef int I;
  class Y { /* ... */ };
  I a;
};

I b;                            // error
Y c;                            // error
X::Y d;                         // OK
X::I e;                         // OK

end example]

12.3 Unions [class.union]

В объединении нестатический член данных - это active если его имя относится к объекту, lifetime который начался и не закончился. Максимум один из нестатических элементов данных объекта типа объединения может быть активным в любое время, то есть значение не более одного из нестатических элементов данных может быть сохранено в объединении в любое время. [ Note: Одна специальная гарантия дается для упрощения использования объединений: если объединение стандартного макета содержит несколько структур стандартного макета, которые совместно используют a common initial sequence, и если нестатический член данных объекта этого типа объединения стандартного макета является active и является одной из структур стандартного макета, разрешается проверять общую начальную последовательность любого из членов структуры стандартного макета; см [class.mem]. ]end note

Размер объединения достаточен, чтобы содержать самый большой из его нестатических элементов данных. Каждый нестатический член данных выделяется, как если бы он был единственным членом структуры. [ Note: Объект объединения и его нестатические элементы данных - это pointer-interconvertible ([expr.static.cast]). Как следствие, все нестатические элементы данных объекта объединения имеют один и тот же адрес. ]end note

Объединение может иметь функции-члены (включая конструкторы и деструкторы), но не должно иметь virtual функций. У союза не должно быть базовых классов. Объединение не должно использоваться в качестве базового класса. Если объединение содержит нестатический элемент данных ссылочного типа, программа имеет неправильный формат. [ Note: Отсутствует default member initializers, если не-статический член данных объединения имеет нетривиальный конструктор по умолчанию ([class.ctor]), copy constructor, конструктор перемещения ([class.copy]), copy assignment operator, move assignment operator, или destructor, соответствующая функция члена союза должна быть предоставленный пользователем или он будет неявно deleted для союза. ] end note

[ Example: Рассмотрим следующий союз:

union U {
  int i;
  float f;
  std::string s;
};

Поскольку std​::​string объявляет нетривиальные версии всех специальных функций-членов, U будет неявно удален конструктор по умолчанию, конструктор копирования / перемещения, оператор присваивания / перемещения и деструктор. Для использования Uнекоторые или все эти функции-члены должны быть предоставлены пользователем. ]end example

Когда левый операнд оператора присваивания включает в себя, member access expression который назначает член объединения, он может начать время жизни этого члена объединения, как описано ниже. Для выражения Eопределите набор S(E) подвыражений E следующим образом:

  • Если E имеет форму A.B, S(E) содержит элементы S(A), а также содержит, A.B если B имена, член объединения неклассового, не-массивного типа или типа класса с тривиальным конструктором по умолчанию, который не удаляется, или массив таких типы.

  • Если E имеет форму A[B] и интерпретируется как встроенный оператор индексации массива, S(E) is S(A) if A имеет тип массива, S(B) if B имеет тип массива и пусто в противном случае.

  • В противном случае S(E) пусто.

В выражении присваивания формы , E1 = E2 которая использует либо built-in assignment operator или trivial assignment operator, для каждого элемента X из S(E1), если модификация X будет иметь неопределенное поведение под [basic.life], объектом типа X неявно создаются в выдвинутом хранении; инициализация не выполняется, и начало его жизненного цикла упорядочивается после вычисления значений левого и правого операндов и перед назначением. [На Note: этом заканчивается lifetime членство ранее активного члена союза, если таковой имеется. ] [end noteExample:

union A { int x; int y[4]; };
struct B { A a; };
union C { B b; int k; };
int f() {
  C c;                  // does not start lifetime of any union member
  c.b.a.y[3] = 4;       // OK: S(c.b.a.y[3]) contains c.b and c.b.a.y;
                        // creates objects to hold union members c.b and c.b.a.y
  return c.b.a.y[3];    // OK: c.b.a.y refers to newly created object (see [basic.life])
}

struct X { const int a; int b; };
union Y { X x; int k; };
void g() {
  Y y = { { 1, 2 } };   // OK, y.x is active union member ([class.mem])
  int n = y.x.a;
  y.k = 4;              // OK: ends lifetime of y.x, y.k is active member of union
  y.x.b = n;            // undefined behavior: y.x.b modified outside its lifetime,
                        // S(y.x.b) is empty because X's default constructor is deleted,
                        // so union member y.x's lifetime does not implicitly start
}

end example]

[ Note: В общем, new-expressionдля изменения активного члена объединения необходимо использовать явные вызовы деструктора и размещение . ] [ Рассмотрим объект из более типа , имеющей не-статические элементы данных типа и типа . Если есть ненулевая деструктор и имеет нетривиальный конструктор (например, если они объявляют или наследовать виртуальные функции), активный член может быть безопасно переключаются с с использованием деструктора и размещений следующим образом : end noteExample: u union U m M n N M N u m n new-expression

u.m.~M();
new (&u.n) N;

end example]

12.3.1 Anonymous unions [class.union.anon]

Союз формы

union { member-specification } ;

называется anonymous union; он определяет безымянный тип и безымянный объект этого типа, называемый anonymous union object. Каждый member-declarationв member-specification анонимном союзе должен либо определить нестатический элемент данных или быть static_assert-declaration. [ Note: Вложенные типы, анонимные объединения и функции не могут быть объявлены в анонимном объединении. ] Имена членов анонимного объединения должны отличаться от имен любых других объектов в области, в которой объявлено анонимное объединение. В целях поиска имени после определения анонимного объединения члены анонимного объединения считаются определенными в области, в которой объявлено анонимное объединение. [end noteExample:

void f() {
  union { int a; const char* p; };
  a = 1;
  p = "Jennifer";
}

Здесь a и p используются как обычные (не являющиеся членами) переменные, но поскольку они являются членами объединения, у них одинаковый адрес. ]end example

Анонимные объединения, объявленные в именованном пространстве имен или в глобальном пространстве имен, должны быть объявлены static. Анонимные объединения, объявленные в области видимости блока, должны быть объявлены с любым классом хранения, разрешенным для переменной области видимости блока, или без класса хранения. Класс хранения не допускается в объявлении анонимного объединения в области действия класса. Анонимный союз не может иметь членов или (пункт ). Анонимный союз не должен иметь функций-членов. private protected [class.access]

Объединение, для которого объявлены объекты, указатели или ссылки, не является анонимным объединением. [Example:

void f() {
  union { int aa; char* p; } obj, *ptr = &obj;
  aa = 1;           // error
  ptr->aa = 1;      // OK
}

Присвоение plain aa неверно сформировано, поскольку имя члена не видно за пределами объединения, и даже если оно было видимым, оно не связано с каким-либо конкретным объектом. ] [ Инициализация объединений без конструкторов, объявленных пользователем, описана в . ]end exampleNote: [dcl.init.aggr]end note

A union-like class - это объединение или класс, прямым членом которого является анонимный союз. Класс, подобный объединению, X имеет набор variant members. Если X это объединение, нестатический член данных, X который не является анонимным объединением, является его вариантным членом X. Кроме того, нестатический член данных анонимного союза, который является членом, X также является вариантным членом X. Не более одного варианта члена объединения может иметь инициализатор члена по умолчанию. [Example:

union U {
  int x = 0;
  union {
    int k;
  };
  union {
    int z;
    int y = 1;      // error: initialization for second variant member of U
  };
};

end example]

12.4 Local class declarations [class.local]

Класс может быть объявлен в определении функции; такой класс называется local классом. Имя локального класса является локальным для окружающей его области видимости. Локальный класс находится в области охватывающей области и имеет такой же доступ к именам вне функции, как и включающая функция. Объявления в локальном классе не должны быть odr-use переменной с автоматической продолжительностью хранения из охватывающей области. [Example:

int x;
void f() {
  static int s;
  int x;
  const int N = 5;
  extern int q();

  struct local {
    int g() { return x; }       // error: odr-use of automatic variable x
    int h() { return s; }       // OK
    int k() { return ::x; }     // OK
    int l() { return q(); }     // OK
    int m() { return N; }       // OK: not an odr-use
    int* n() { return &N; }     // error: odr-use of automatic variable N
  };
}

local* p = 0;                   // error: local not in scope

end example]

Вмещающая функция не имеет специального доступа к членам локального класса; он подчиняется обычному access rules. Функции-члены локального класса должны быть определены в их определении класса, если они вообще определены.

Если класс X является локальным классом, вложенный класс Y может быть объявлен в классе X и позже определен в определении класса X или позже определен в той же области, что и определение класса X. Класс, вложенный в локальный класс, является локальным классом.

Локальный класс не должен иметь статических элементов данных.