Нестатические данные-члены
Нестатические данные-члены объявляются в определении члена класса.
class S
{
int n; // non-static data member
int& r; // non-static data member of reference type
int a[2] = {1, 2}; // non-static data member with default member initializer (C++11)
std::string s, *ps; // two non-static data members
struct NestedS
{
std::string s;
} d5; // non-static data member of nested type
char bit : 2; // two-bit bitfield
};Разрешены любые простые объявления, за исключением
| (с C++11) |
- неполные типы, абстрактные типы классов и массивы из них не допускаются: в частности, класс
Cне может иметь нестатический данные-член типаC, хотя он может иметь нестатический данные-член типаC&(ссылка на C) илиC*(указатель на C); - нестатический данные-член не может иметь то же имя, что и имя класса, если присутствует хотя бы один объявленный пользователем конструктор;
| (с C++11) |
Кроме того, допускаются объявления битовых полей.
Макет
При создании объекта некоторого класса C, каждый нестатический данные-член типа, не являющегося ссылкой, выделяется в некоторой части представления объекта C. Занимают ли члены-ссылки какое-либо место в памяти, определяется реализацией, но их срок хранения совпадает со сроком хранения объекта, в котором они являются членами.
| Для типов класса, не являющихся объединениями, члены ненулевого размера(с C++20) не отделённые спецификатором доступа(до C++11)с тем же доступом к члену(с C++11) всегда выделяются так, что члены, объявленные позже, имеют более высокие адреса в объекте класса. Члены отделённые спецификатором доступа(до C++11)с различным контролем доступа(с C++11) выделяются в неопределённом порядке (компилятор может сгруппировать их вместе). | (до C++23) |
| Для типов класса, не являющихся объединениями, члены ненулевого размера всегда выделяются так, что члены, объявленные позже, имеют более высокие адреса в объекте класса. Обратите внимание, что контроль доступа к члену всё ещё влияет на свойство стандартного макета (см. ниже). | (с C++23) |
Требования к выравниванию могут потребовать заполнения между членами или после последнего члена класса.
Стандартный макет
| Класс считается стандартным макетом и обладает описанными ниже свойствами, если и только если он является POD-классом. | (до C++11) |
| Класс, в котором все нестатические данные-члены имеют одинаковый контроль доступа и удовлетворяют определённым другим условиям, называется классом со стандартным макетом (см. класс со стандартным макетом для списка требований). | (с C++11) |
Общая начальная последовательность двух типов класса со стандартным макетом, не являющихся объединениями, представляет собой самую длинную последовательность нестатических данных-членов и битовых полей в порядке объявления, начиная с первого такого элемента в каждом из классов, при этом
| (с C++20) |
- соответствующие элементы имеют типы, совместимые с макетом,
- соответствующие элементы имеют одинаковые требования к выравниванию, и
- либо оба элемента являются битами полей с одинаковой шириной, либо ни один из них не является битовым полем.
struct A { int a; char b; };
struct B { const int b1; volatile char b2; };
// A and B's common initial sequence is A.a, A.b and B.b1, B.b2
struct C { int c; unsigned : 0; char b; };
// A and C's common initial sequence is A.a and C.c
struct D { int d; char b : 4; };
// A and D's common initial sequence is A.a and D.d
struct E { unsigned int e; char b; };
// A and E's common initial sequence is emptyДва типа класса со стандартным макетом, не являющихся объединениями, называются совместимыми по макету, если они являются одним и тем же типом, игнорируя модификаторы cv, если таковые имеются, если они являются перечислениями (т.е. перечислениями с одним и тем же базовым типом), совместимыми по макету, или если их общая начальная последовательность состоит из всех нестатических данных-членов и битовых полей (в примере выше, A и B совместимы по макету).
Два стандартных объединения называются совместимыми по макету, если они имеют одинаковое количество нестатических данных-членов, и соответствующие нестатические данные-члены (в любом порядке) имеют типы, совместимые по макету.
Типы со стандартным макетом обладают следующими специальными свойствами:
- В стандартном объединении с активным членом типа класса, не являющегося объединением,
T1, разрешается читать нестатический данные-членmдругого члена объединения типа класса, не являющегося объединением,T2, при условии, чтоmявляется частью общей начальной последовательностиT1иT2(за исключением того, что чтение переменной volatile через не-volatile glvalue неопределено). - Указатель на объект типа класса со стандартным макетом может быть
reinterpret_castв указатель на его первый нестатический небитовое данных-член (если у него есть нестатические данные-члены) или в любой другой его подобъект базового класса (если таковые имеются), и наоборот. Другими словами, заполнение не допускается перед первым данных-членом типа со стандартным макетом. Обратите внимание, что правила жёсткого алиасирования всё ещё применяются к результату такого преобразования. - Макрос
offsetofможет использоваться для определения смещения любого члена от начала класса со стандартным макетом.
Инициализация членов
Нестатические данные-члены могут быть инициализированы одним из двух способов:
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-> выражения доступа к членам, которые появляются, когда имя нестатического члена используется в любом контексте, где разрешено 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: use of m to make a pointer to member
void (S::*fp)() = &S::f; // OK: use of f to make a pointer to memberstruct S
{
int m;
static const std::size_t sz = sizeof m; // OK: m in unevaluated operand
};
std::size_t j = sizeof(S::m + 42); // OK: even though there is no "this" object for 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 | общая последовательность инициализации не учитывала требования выравнивания | учитывались |
См. также
| классы | |
| статические члены | |
| нестатические функции-члены | |
|
(C++11) | проверяет, является ли тип стандартным типом компоновки (шаблон класса) |
| смещение байтов от начала стандартного типа компоновки до указанного члена (макрос функции) |
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/data_members