Non-static data members
Нестатические члены данных объявляются в спецификации членов класса.
class S { int n; // нестатический член данных int& r; // нестатический член данных ссылочного типа int a[2] = {1, 2}; // нестатический член данных с инициализатором по умолчанию (C++11) std::string s, *ps; // два нестатических члена данных struct NestedS { std::string s; } d5; // нестатический член данных вложенного типа char bit : 2; // двухбитовое битовое поле };
Любые простые объявления разрешены, за исключением
|
(since C++11) |
-
неполные типы
,
абстрактные классы
и их массивы не допускаются: в частности, класс
Cне может иметь нестатический член данных типаC, хотя он может иметь нестатический член данных типаC&(ссылка на C) илиC*(указатель наC); - нестатический член данных не может иметь то же имя, что и имя класса, если присутствует хотя бы один пользовательский конструктор;
|
(since C++11) |
Кроме того, bit-field объявления разрешены.
Содержание |
Компоновка
Когда объект некоторого класса
C
создается, каждый нестатический член данных нессылочного типа размещается в некоторой части представления объекта
C
. Занимают ли ссылочные члены память, определяется реализацией, но их
storage duration
совпадает с продолжительностью хранения объекта, членами которого они являются.
|
Для не- union типов классов, non-zero-sized (since C++20) члены не разделённые access specifier (until C++11) с одинаковым member access (since C++11) всегда размещаются так, что члены, объявленные позже, имеют более высокие адреса в объекте класса. Члены разделённые access specifier (until C++11) с различным управлением доступом (since C++11) размещаются в неуказанном порядке (компилятор может сгруппировать их вместе). |
(until C++23) |
|
Для не- union типов классов, non-zero-sized члены всегда размещаются так, что члены, объявленные позже, имеют более высокие адреса в объекте класса. Обратите внимание, что управление доступом членов всё ещё влияет на свойство standard-layout (см. ниже). |
(since C++23) |
Требования выравнивания могут потребовать заполнения между членами или после последнего члена класса.
Стандартная компоновка
|
Класс считается стандартным по размещению и обладает свойствами, описанными ниже, тогда и только тогда, когда он является POD-классом . |
(до C++11) |
|
Класс, в котором все нестатические члены данных имеют одинаковый контроль доступа и удовлетворяются определенные другие условия, известен как стандартный по размещению класс (см. стандартный по размещению класс для списка требований). |
(начиная с C++11) |
общая начальная последовательность двух типов стандартной компоновки, не являющихся объединениями, представляет собой самую длинную последовательность нестатических членов данных и битовых полей в порядке объявления, начиная с первой такой сущности в каждом из классов, такая что
|
(начиная с C++20) |
- соответствующие сущности имеют layout-совместимые типы,
- соответствующие сущности имеют одинаковые требования к выравниванию , и
- либо обе сущности являются битовыми полями одинаковой ширины, либо ни одна из них не является битовым полем.
struct A { int a; char b; }; struct B { const int b1; volatile char b2; }; // Общая начальная последовательность A и B: A.a, A.b и B.b1, B.b2 struct C { int c; unsigned : 0; char b; }; // Общая начальная последовательность A и C: A.a и C.c struct D { int d; char b : 4; }; // Общая начальная последовательность A и D: A.a и D.d struct E { unsigned int e; char b; }; // Общая начальная последовательность A и E: пустая
Два типа не-объединений со стандартной компоновкой называются
layout-compatible
(совместимыми по компоновке), если они являются одним и тем же типом без учета cv-квалификаторов (если таковые имеются), являются layout-compatible
перечислениями
(т.е. перечислениями с одинаковым базовым типом), или если их
common initial sequence
(общая начальная последовательность) состоит из каждого нестатического члена данных и битового поля (в примере выше,
A
и
B
являются layout-compatible).
Два стандартно размещённых объединения называются layout-compatible если они имеют одинаковое количество нестатических членов данных и соответствующие нестатические члены данных (в любом порядке) имеют layout-compatible типы.
Стандартно-компонуемые типы обладают следующими особыми свойствами:
-
-
В стандартном layout-объединении с активным членом не-объединенного типа класса
T1разрешается читать нестатический член данныхmдругого члена объединения не-объединенного типа классаT2при условии, чтоmявляется частью общей начальной последовательностиT1иT2(за исключением того, что чтение volatile-члена через не-volatile glvalue является неопределенным поведением). -
Указатель на объект стандартного layout-типа класса может быть
reinterpret_castв указатель на его первый нестатический не-битовый член данных (если он имеет нестатические члены данных) или в указатель на любой из его базовых подобъектов (если они есть), и наоборот. Другими словами, выравнивание не допускается перед первым членом данных стандартного layout-типа. Обратите внимание, что правила строгого псевдонимирования все еще применяются к результату такого приведения. - Макрос offsetof может использоваться для определения смещения любого члена от начала стандартного layout-класса.
-
В стандартном layout-объединении с активным членом не-объединенного типа класса
Инициализация членов класса
Нестатические члены данных могут быть инициализированы одним из двух способов:
struct S { int n; std::string s; S() : n(7) {} // direct-initializes n, default-initializes s };
|
2)
С помощью
инициализатора члена по умолчанию
, который представляет собой фигурный или знаковый
инициализатор
, включенный в объявление члена, и используется, если член опущен из списка инициализации членов конструктора.
struct S { int n = 7; std::string s{'a', 'b', 'c'}; S() {} // default member initializer will copy-initialize n, list-initialize s }; Если член имеет инициализатор по умолчанию и также появляется в списке инициализации членов в конструкторе, инициализатор члена по умолчанию игнорируется для этого конструктора.
Запустить код
#include <iostream> int x = 0; struct S { int n = ++x; S() {} // uses default member initializer S(int arg) : n(arg) {} // uses member initializer }; int main() { std::cout << x << '\n'; // prints 0 S s1; // default initializer ran std::cout << x << '\n'; // prints 1 S s2(7); // default initializer did not run std::cout << x << '\n'; // prints 1 }
Члены массива не могут выводить свой размер из инициализаторов членов: struct X { int a[] = {1, 2, 3}; // error int b[3] = {1, 2, 3}; // OK }; Инициализаторы членов по умолчанию не могут вызывать неявное определение сгенерированного конструктора по умолчанию для включающего класса или спецификации исключений этого конструктора: struct node { node* p = new node; // error: use of implicit or defaulted node::node() }; Ссылочные члены не могут быть привязаны к временным объектам в инициализаторе члена по умолчанию (примечание: такое же правило существует для списков инициализации членов ): struct A { A() = default; // OK A(int v) : v(v) {} // OK const int& v = 42; // OK }; A a1; // error: ill-formed binding of temporary to reference A a2(1); // OK (default member initializer ignored because v appears in a constructor) // however a2.v is a dangling reference |
(начиная с C++11) |
|
Если ссылочный член инициализируется из своего инициализатора по умолчанию (до C++20) член имеет инициализатор по умолчанию (начиная с C++20) и потенциально вычисляемое подвыражение этого инициализатора является агрегатной инициализацией , которая использовала бы этот инициализатор по умолчанию, программа является некорректной: struct A; extern A a; struct A { const A& a1{A{a, a}}; // OK const A& a2{A{}}; // error }; A a{a, a}; // OK |
(начиная с C++17) |
Использование
Имя нестатического члена данных или нестатической функции-члена может появляться только в следующих трёх ситуациях:
this
разрешён (внутри тел функций-членов, в списках инициализации членов, во внутриклассовых инициализаторах членов по умолчанию).
struct S { int m; int n; int x = m; // OK: implicit this-> allowed in default initializers (C++11) S(int i) : m(i), n(m) // OK: implicit this-> allowed in member initializer lists { this->f(); // explicit member access expression f(); // implicit this-> allowed in member function bodies } void f(); };
struct S { int m; void f(); }; int S::*p = &S::m; // OK: использование m для создания указателя на член void (S::*fp)() = &S::f; // OK: использование f для создания указателя на член
struct S { int m; static const std::size_t sz = sizeof m; // OK: m в невычисляемом операнде }; std::size_t j = sizeof(S::m + 42); // OK: даже несмотря на отсутствие объекта "this" для m
Примечания
| Макрос тестирования возможностей | Значение | Стандарт | Возможность |
|---|---|---|---|
__cpp_nsdmi
|
200809L
|
(C++11) | Инициализаторы нестатических членов данных |
__cpp_aggregate_nsdmi
|
201304L
|
(C++14) | Агрегатные классы с инициализаторами членов по умолчанию |
Отчёты о дефектах
Следующие отчеты об изменениях в поведении, являющиеся дефектными, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
| CWG 80 | C++98 |
все члены данных не могут иметь то же имя,
что и имя класса (нарушает совместимость с C) |
разрешить нестатическим членам данных
использовать имя класса, если нет пользовательского конструктора |
| CWG 190 | C++98 |
при определении совместимости размещения
рассматривались все члены |
рассматривать только не-
статические члены данных |
| CWG 613 | C++98 | невычисленные использования нестатических членов данных не разрешены | такие использования разрешены |
| CWG 645 | C++98 |
не было указано, являются ли битовые поля и
не-битовые поля совместимыми по размещению |
не совместимы по размещению |
| CWG 1397 | C++11 |
класс считался полным
в инициализаторах членов по умолчанию |
инициализатор члена по умолчанию не может вызвать
определение конструктора по умолчанию |
| CWG 1425 | C++98 |
было неясно, разделяет ли стандартно размещаемый объект
тот же адрес с первым нестатическим членом данных или первым подобъектом базового класса |
нестатический член данных
если присутствует, иначе подобъект базового класса если присутствует |
| CWG 1696 | C++98 |
ссылочные члены могли быть инициализированы временными объектами
(время жизни которых заканчивалось в конце конструктора) |
такая инициализация некорректна |
| CWG 1719 | C++98 | типы с разной cv-квалификацией не были совместимы по размещению | cv-квалификаторы игнорируются, спецификация улучшена |
| CWG 2254 | C++11 |
указатель на стандартно размещаемый класс без данных
членов может быть reinterpret_cast к его первому базовому классу |
может быть reinterpret_cast
к любому из его базовых классов |
| CWG 2583 | C++11 |
общая начальная последовательность не
учитывала требования выравнивания |
учитываются |
| CWG 2759 | C++20 |
общая начальная последовательность могла включать
члены, объявленные
[[
no_unique_address
]]
|
они не включаются |
Смотрите также
| классы | |
| статические члены | |
| нестатические функции-члены | |
|
(C++11)
|
проверяет, является ли тип
стандартным расположением
(шаблон класса) |
|
байтовое смещение от начала типа
стандартного расположения
до указанного члена
(функция-макрос) |
|