Пространства имён
Варианты
Действия

Конструкторы и списки инициализаторов элементов

Материал из cppreference.com
< cpp‎ | language
 
 
Язык С++
Общие темы
Управление потоком
Операторы условного выполнения
Операторы итерации (циклы)
Операторы перехода
Функции
Объявление функции
Выражение лямбда-функции
Спецификатор inline
Спецификации динамических исключений(до C++17*)
Спецификатор noexcept(C++11)
Исключения
Пространства имён
Типы
Спецификаторы
decltype(C++11)
auto(C++11)
alignas(C++11)
Спецификаторы длительности хранения
Инициализация
Выражения
Альтернативные представления
Литералы
Логические - Целочисленные - С плавающей запятой
Символьные - Строковые - nullptr(C++11)
Определяемые пользователем(C++11)
Утилиты
Атрибуты(C++11)
Types
Объявление typedef
Объявление псевдонима типа(C++11)
Casts
Неявные преобразования - Явные преобразования
static_cast - dynamic_cast
const_cast - reinterpret_cast
Выделение памяти
Классы
Свойства функции класса
Специальные функции-элементы
Шаблоны
Разное
 

Конструктор это специальная нестатическая функция-элемент класса, которая используется для инициализации объектов своего классового типа.

В определении конструктора класса список инициализаторов элементов определяет инициализаторы для прямых и виртуальных базовых классов, а также нестатических элементов класса. (Не путать с std::initializer_list.)

Конструктор не может быть сопрограммой.

(начиная с C++20)

Конструктор не может иметь явный параметр объекта.

(начиная с C++23)

Содержание

[править]Синтаксис

Конструкторы определяются с помощью деклараторов функций элементов в следующем формате:

имя-класса(список-параметров (необязательно))спецификатор-except (необязательно)атрибуты (необязательно) (1)

Где имя-класса должно быть именем текущего класса (или текущей специализации шаблона класса), или, при объявлении в области видимости пространства имён или в объявлении друга, оно должно быть полным именем класса.

Единственными спецификаторами, разрешёнными в последовательности-деклараторов-объявления объявления конструктора, являются friend, inline, constexpr(начиная с C++11), consteval(начиная с C++20) и explicit (в частности, возвращаемый тип не разрешён). Обратите внимание, что cv- и ссылочные-квалификаторы также не допускаются: const и volatile семантики строящегося объекта не вступают в силу, пока не завершится самый производный конструктор.

Тело определения функции любого конструктора перед открывающей фигурной скобкой составного оператора может включать список инициализаторов элементов, синтаксис которого представляет собой символ двоеточия :, за которым следует разделённый запятыми список одного или нескольких инициализаторов-элементов, каждый из которых имеет следующий синтаксис:

Тело функции любого конструктора, до открывающей скобки составного выражения, может включать список инициализации элементов класса, чей синтаксис состоит из знака двоеточия :, за которым следует разделённый запятой список из одного или более инициализатора-элемента-класса со следующим синтаксисом

класс-или-идентификатор(список-выражений (необязательно)) (1)
класс-или-идентификаторсписок-инициализации-в-фигурных-скобках (2) (начиная с C++11)
пакет-параметров... (3) (начиная с C++11)
1) Инициализирует базовый класс или элемент текущего класса с именем класс-или-идентификатор используя прямую инициализацию или, если список-выражений пуст, инициализацию значением
2) Инициализирует базовый класс или элемент текущего класса с именем класс-или-идентификатор используя инициализацию списком (которая становится инициализацией значением, если список пустой, или агрегирующей инициализацией, при инициализации агрегата)
3) Инициализирует несколько базовых классов, используя расширение пакета
класс-или-идентификатор любой идентификатор, который именует нестатический элемент данных, или любое имя типа, которое именует либо сам класс (для делегирования конструкторов), либо прямой или виртуальный базовый класс.
список-выражений возможно пустой список аргументов, разделённых запятыми, для передачи конструктору базового класса или элементу
список-инициализации-в-фигурных-скобках заключённый в фигурные скобки список инициализаторов, разделённых запятыми, и вложенные списки инициализации в фигурных скобках
пакет-параметров имя пакета параметров шаблона с переменным числом аргументов
struct S {int n; S(int);// объявление конструктора S(): n(7){}// определение конструктора.// ": n(7)" это список инициализаторов// ": n(7) {}" это тело функции}; S::S(int x): n{x}{}// определение конструктора. ": n{x}" это список инициализаторовint main(){ S s;// вызывает S::S() S s2(10);// вызывает S::S(int)}

[править]Объяснение

У конструкторов нет имени и их нельзя вызывать напрямую. Они вызываются, когда происходит инициализация, и выбираются согластно правилам инициализации. Конструкторы без спецификатора explicit яляются конвертирующими конструкторами. Конструкторы со спецификатором constexpr делают свой тип LiteralType. Конструкторы, которые можно вызвать без аргументов, являются конструкторами по умолчанию. Конструкторы, принимающие в качестве аргумента другой объект того же типа, являются конструкторами копирования и конструкторами перемещения.

Прежде чем составной оператор, формирующий тело функции конструктора, начнёт выполняться, инициализация всех прямых базовых классов, виртуальных базовых классов и нестатических элементов данных будет завершена. Список инициализаторов элементов это место, где можно указать инициализацию этих объектов не по умолчанию. Для базовых и нестатических элементов данных, которые не могут быть инициализированы по умолчанию, таких как элементы ссылочных и константных типов, необходимо указать инициализаторы элементов. Инициализация не выполняется для анонимных объединений или вариантных элементов, у которых нет инициализатора .

Инициализаторы, в которых класс-или-идентификатор именуют виртуальный базовый класс, игнорируются при создании любого класса, который не является наиболее производным классом создаваемого объекта.

Имена, которые перечислены в списке-выражений или списке-инициализации-в-фигурных-скобках, вычисляются в области видимости конструктора:

class X {int a, b, i, j;public:constint& r; X(int i): r(a)// инициализирует X::r ссылкой на X::a , b{i}// инициализирует X::b значением параметра i , i(i)// инициализирует X::i значением параметра i , j(this->i)// инициализирует X::j значением X::i{}};

Исключения, которые выбрасывает инициализатор элемента класса, могут обрабатываться блоком-try-функции.

Функции-элементы (включая виртуальные функции) могут быть вызваны в инициализаторах элементов класса, но поведение не определено, если не все прямые базовые классы инициализированы к этому моменту.

Для вызова виртуальных функций (если все прямые базовые классы инициализированы к тому моменту) применяются те же правила, что и для вызова виртуальных функций из конструкторов и деструкторов: виртуальные функции-элементы ведут себя так, как если бы динамический тип *this был бы статическим типом создаваемого класса (динамическая отправка не спускается дальше по иерархии наследования), а виртуальные вызовы (но не статические вызовы) чистых виртуальных функций элементов приводят к неопределённому поведению.

Если нестатический элемент данных имеет инициализатор по умолчанию и этот элемент класса появляется в списке инициализаторов элементов, тогда используется инициализатор из списка, а инициализатор по умолчанию игнорируется:

struct S {int n =42;// инициализатор элемента по умолчанию S(): n(7){}// установит n в 7, не в 42};
(начиная с C++11)

Ссылочные элементы не могут быть привязаны к временным элементам в списке инициализаторов элементов:

struct A { A(): v(42){}// Ошибкаconstint& v;};

Примечание: то же самое относится к инициализатору элемента по умолчанию

(начиная с C++14)

Делегирующий конструктор

Если имя класса появляется как класс-или-идентификатор в списке инициализаторов элементов, тогда список должен состоять только из этого одного инициализатора элемента; такой конструктор называется делегирующим конструктором, а конструктор, выбранный единственным элементом списка инициализаторов, называется целевым конструктором.

В этом случае целевой конструктор выбирается путём разрешения перегрузки и выполняется первым, затем управление возвращается к делегирующему конструктору, и выполняется его тело.

Делегирующий конструктор не может быть рекурсивным.

class Foo {public: Foo(char x, int y){} Foo(int y): Foo('a', y){}// Foo(int) делегирует Foo(char,int)};

Наследование конструкторов

Смотрите using-объявление.

(начиная с C++11)

[править]Порядок инициализации

Порядок инициализаторов элементов в списке не имеет значения: фактический порядок инициализации следующий:

1) Если конструктор предназначен для наиболее производного класса, виртуальные базовые классы инициализируются в том порядке, в котором они появляются при обходе в глубину слева направо объявлений базового класса (слева направо относится к появлению в списках спецификаторов базового класса)
2) Затем инициализируются прямые базовые классы в порядке слева направо по мере их появления в списке спецификаторов базового класса этого класса
3) Затем инициализируются нестатические элементы данных в порядке объявления в определении класса.
4) Наконец, выполняется тело конструктора

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

[править]Примечание

Макрос Тестирования функциональностиЗначениеСтандартФункциональность
__cpp_delegating_constructors200604L(C++11)Делегирование конструкторов

[править]Пример

#include <fstream>#include <string>#include <mutex>   struct Base {int n;};   struct Class :public Base {unsignedchar x;unsignedchar y;std::mutex m;std::lock_guard<std::mutex> lg;std::fstream f;std::string s;   Class (int x ): Base {123}, // инициализация базового класса x ( x ), // x (элемент) инициализируется с помощью x (параметр) y {0}, // у инициализируется 0 f{"test.cc", std::ios::app}, // это происходит после инициализации m и lg s(__func__), //__func__ доступен, потому что список инициализации является// частью конструктора lg ( m ), // lg использует m, который уже инициализирован m{}// m инициализируется перед lg, хотя здесь он появляется последним{}// пустой составной оператор   Class (double a ): y ( a+1), x ( y ), // x будет инициализирован перед y, его значение здесь неопределенное lg ( m ){}// инициализатор базового класса не отображается в списке, он инициализируется// по умолчанию// (не то же самое, как если бы использовался Base(), который является// инициализацией значением)   Class()try// блок функции try начинается перед телом функции, которое включает в себя// список инициализации: Class(0.0)//конструктор делегат{// ...}catch(...){// исключение произошло при инициализации}};   int main(){ Class c; Class c1(1); Class c2(0.1);}

[править]Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 194 C++98 синтаксис декларатора конструктора допускал не более
одного спецификатора функции (например, конструктор
не может быть объявлен inlineexplicit)
разрешено несколько спецификаторов функций
CWG 257 C++98 не было указано, должен ли абстрактный класс
предоставлять инициализаторы элементов для своих
виртуальных базовых классов
указано как необязательное, и такие
инициализаторы элементов игнорируются
во время выполнения
CWG 263 C++98 синтаксис декларатора конструктора запрещает
конструкторам дружить
разрешено конструкторам дружить
CWG 1345 C++98 элементы анонимных объединений без инициализаторов
элементов по умолчанию инициализировались по умолчанию
они не инициализируются
CWG 1435 C++98 значение 'имя класса' в синтаксисе конструктора
декларатора было неясным
синтаксис изменился на специализированный
синтаксис декларатора функций
CWG 1696 C++98 ссылочные элементы могут быть инициализированы
временными значениями (жизнь которых заканчивается
в конце конструктора)
такая инициализация некорректна

[править]Ссылки

  • C++23 стандарт (ISO/IEC 14882:2023):
  • 11.4.5 Конструкторы [class.ctor]
  • 11.9.3 Инициализация базовых классов и элементов [class.base.init]
  • C++20 стандарт (ISO/IEC 14882:2020):
  • 11.4.4 Конструкторы [class.ctor]
  • 11.10.2 Инициализация базовых классов и элементов [class.base.init]
  • C++17 стандарт (ISO/IEC 14882:2017):
  • 15.1 Конструкторы [class.ctor]
  • 15.6.2 Инициализация базовых классов и элементов [class.base.init]
  • C++14 стандарт (ISO/IEC 14882:2014):
  • 12.1 Конструкторы [class.ctor]
  • 12.6.2 Инициализация базовых классов и элементов [class.base.init]
  • C++11 стандарт (ISO/IEC 14882:2011):
  • 12.1 Конструкторы [class.ctor]
  • 12.6.2 Инициализация базовых классов и элементов [class.base.init]
  • C++98 стандарт (ISO/IEC 14882:1998):
  • 12.1 Конструкторы [class.ctor]
  • 12.6.2 Инициализация базовых классов и элементов [class.base.init]

[править]Смотрите также

close