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 ]