Spec-Zone.ru › C++

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

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

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

class="t-rev-begin">

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

(с C++20)
class="t-rev-begin">

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

(с C++23)

Синтаксис

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

class="t-sdsc-begin">
имя-класса ( список-параметров (необязательно) ) исключение-спецификация (необязательно) атрибут (необязательно) (1)

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

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

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

class="t-sdsc-begin">
идентификатор-или-имя-класса ( список-выражений (необязательно) ) (1)
идентификатор-или-имя-класса список-инициализации (2) (с C++11)
пакет-параметров ... (3) (с C++11)
1) Инициализирует базовый или член, указанный идентификатор-или-имя-класса с помощью прямой инициализации или, если список-выражений пуст, с помощью инициализации значением
2) Инициализирует базовый или член, указанный идентификатор-или-имя-класса с помощью инициализации списком (что становится инициализацией значением, если список пустой, и инициализацией агрегата при инициализации агрегата)
3) Инициализирует несколько баз с помощью расширения пакета
class="t-par-begin">
идентификатор-или-имя-класса - любой идентификатор, который называет нестатический член данных или любое имя типа, которое называет сам класс (для делегирующих конструкторов) или прямой или виртуальный базовый класс.
список-выражений - , возможно, пустой, перечисленный через запятую список аргументов, передаваемых конструктору базового класса или члена.
список-инициализации - список, заключенный в фигурные скобки, из перечисленных через запятые инициализаторов и вложенных списков инициализации
пакет-параметров - имя универсального шаблона пакета параметров
struct S
{
    int n;
 
    S(int);       // constructor declaration
 
    S() : n(7) {} // constructor definition:
                  // ": n(7)" is the initializer list
                  // ": n(7) {}" is the function body
};
 
S::S(int x) : n{x} {} // constructor definition: ": n{x}" is the initializer list
 
int main()
{
    S s;      // calls S::S()
    S s2(10); // calls S::S(int)
}

Объяснение

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

Перед началом выполнения составного оператора, образующего тело функции конструктора, завершается инициализация всех прямых базовых классов, виртуальных базовых классов и нестатических членов данных. Список инициализации членов — это место, где можно указать инициализацию под-объектов, отличную от инициализации по умолчанию. Для базовых классов, которые не могут быть инициализированы по умолчанию, и для нестатических членов данных, которые не могут быть инициализированы по умолчанию или их инициализатором по умолчанию, если он есть(с C++11), таких как члены ссылочного и const-квалифицированного типов, инициализаторы членов должны быть указаны. (Обратите внимание, что инициализаторы членов по умолчанию для нестатических членов данных инстанциаций шаблонов классов могут быть недействительными, если тип члена или инициализатор зависит от шаблона)(с C++11) Инициализация не выполняется для анонимных объединений или членов варианта, которые не имеют инициализатора члена или инициализатора члена по умолчанию(с C++11).

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

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

class X
{
    int a, b, i, j;
public:
    const int& r;
    X(int i)
      : r(a) // initializes X::r to refer to X::a
      , b{i} // initializes X::b to the value of the parameter i
      , i(i) // initializes X::i to the value of the parameter i
      , j(this->i) // initializes X::j to the value of X::i
    {}
};

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

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

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

class="t-rev-begin">

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

struct S
{
    int n = 42;   // default member initializer
    S() : n(7) {} // will set n to 7, not 42
};
(с C++11)

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

struct A
{
    A() : v(42) {} // Error
    const int& v;
};

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

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

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

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

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

class Foo
{
public: 
    Foo(char x, int y) {}
    Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char, int)
};

Наследуемые конструкторы

См. использование объявления.

(с C++11)

Порядок инициализации

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

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

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

Примечания

Макрос проверки функций Значение Std Функция
__cpp_delegating_constructors 200604L (C++11) Делегирующие конструкторы

Пример

#include <fstream>
#include <string>
#include <mutex>
 
struct Base
{
    int n;
};   
 
struct Class : public Base
{
    unsigned char x;
    unsigned char y;
    std::mutex m;
    std::lock_guard<std::mutex> lg;
    std::fstream f;
    std::string s;
 
    Class(int x) : Base{123}, // initialize base class
        x(x),     // x (member) is initialized with x (parameter)
        y{0},     // y initialized to 0
        f{"test.cc", std::ios::app}, // this takes place after m and lg are initialized
        s(__func__), // __func__ is available because init-list is a part of constructor
        lg(m),    // lg uses m, which is already initialized
        m{}       // m is initialized before lg even though it appears last here
    {}            // empty compound statement
 
    Class(double a) : y(a + 1),
        x(y), // x will be initialized before y, its value here is indeterminate
        lg(m)
    {} // base class initializer does not appear in the list, it is
       // default-initialized (not the same as if Base() were used, which is value-init)
 
    Class()
    try // function-try block begins before the function body, which includes init list
      : Class(0.0) // delegate constructor
    {
        // ...
    }
    catch (...)
    {
        // exception occurred on initialization
    }
};
 
int main()
{
    Class c;
    Class c1(1);
    Class c2(0.1);
}

Отчеты об ошибках

Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применён к Поведение, как опубликовано Правильное поведение
CWG 194 C++98 синтаксис декларатора конструктора допускал
не более одного спецификатора функции (например, конструктор
не может быть объявлен inline explicit)
разрешено несколько
спецификаторов функций
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]

См. также

  • исключение копирования
  • конвертирующий конструктор
  • копирующее присваивание
  • копирующий конструктор
  • конструктор по умолчанию
  • деструктор
  • explicit
  • инициализация
    • инициализация агрегатов
    • инициализация констант
    • копирующая инициализация
    • инициализация по умолчанию
    • прямая инициализация
    • инициализация списком
    • инициализация ссылок
    • инициализация значением
    • инициализация нулём
  • перемещающее присваивание
  • перемещающий конструктор
  • new

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/constructor

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API