Класс - это тип. Его имя становится 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 означает «старые добрые данные».
Определение класса вводит новый тип. [ 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 example — end note
[ Note: An elaborated-type-specifierтакже может использоваться type-specifierкак часть объявления. Он отличается от объявления класса тем, что, если класс с подробным именем находится в области видимости, разработанное имя будет ссылаться на него. ] [ — end note Example:
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.
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не объявляет новых членов класса, если он
а using-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 note Note: [basic.compound] [expr.static.cast] — end note
Функция-член может быть 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 note Example:
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 inline — end note
Функции-члены локального класса должны быть определены встроенными в определение их класса, если они вообще определены.
[ 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
Нестатическая функция-член может быть вызвана для объекта своего типа класса или для объекта класса 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 note unqualified-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]).
В теле нестатического 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 note Example:
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
На статический член 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
[ Note: Правила, описанные в [class.mfct] разделе, применяются к статическим функциям-членам. ] — end note
[ Note: Статическая функция-член не имеет this pointer. ] Статической функции-члена быть не должно . Не должно быть статической и нестатической функции-члена с одним и тем же именем и одними и теми же типами параметров ( ). Функция - член статический не должен быть объявлен , или . — end note virtual[over.load] constvolatile const volatile
Статический член данных не является частью подобъектов класса. Если объявлен статический член данных, 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 example — end 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]).
А 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 note constant-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 ]
Класс может быть объявлен внутри другого класса. Класс, объявленный внутри другого, называется nested классом. Имя вложенного класса является локальным для включающего его класса. Вложенный класс находится в области его включающего класса. [ Note: См. [expr.prim] Ограничения на использование нестатических элементов данных и нестатических функций-членов. ] — end note
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 что и класс этого класса, но не имеет особых прав доступа к членам включающего класса.
Имена типов подчиняются точно таким же правилам области видимости, как и другие имена. В частности, имена типов, определенные в определении класса, не могут использоваться вне своего класса без уточнения. [ 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 ]
В объединении нестатический член данных - это 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 note Example:
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 note Example: u union U m M n N M N u m n new-expression
u.m.~M(); new (&u.n) N;
— end example ]
Союз формы
union { member-specification } ;
называется anonymous union; он определяет безымянный тип и безымянный объект этого типа, называемый anonymous union object. Каждый member-declarationв member-specification анонимном союзе должен либо определить нестатический элемент данных или быть static_assert-declaration. [ Note: Вложенные типы, анонимные объединения и функции не могут быть объявлены в анонимном объединении. ] Имена членов анонимного объединения должны отличаться от имен любых других объектов в области, в которой объявлено анонимное объединение. В целях поиска имени после определения анонимного объединения члены анонимного объединения считаются определенными в области, в которой объявлено анонимное объединение. [ — end note Example:
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 example Note: [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 ]
Класс может быть объявлен в определении функции; такой класс называется 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. Функции-члены локального класса должны быть определены в их определении класса, если они вообще определены.