В чем разница между делегированием конструкторов в списке инициализатора члена и в теле конструкторов - PullRequest
0 голосов
/ 13 мая 2018

Конструкторы из C ++ 11 позволяют нам создавать конструкторские цепочки. Например, мы можем закодировать это:

Class Foo
{
public:
    Foo()
    {
    }   

    Foo(int n): Foo()
    {
    }  
};

Я попытался делегировать Foo () как в списке инициализации члена, так и в теле кода. Я получаю одинаковые возвращаемые значения в обеих ситуациях. У меня вопрос, есть ли на самом деле какие-либо различия в обоих методах? Если они одинаковы, есть ли какое-то преимущество перед применением одного над другим?

1 Ответ

0 голосов
/ 13 мая 2018

[class.base.init] / 6 достаточно ясно показывает, как делегировать конструкторы, и это не может быть выполнено в теле конструктора .

Пример

#include <iostream>

struct A
{
    A() : a(42) {}
    A(int) : A() {}

    int a = 17;
};

struct B
{
    B() : b(42) {}
    B(int) { B(); }

    int b = 17;
};

int main()
{
    A a{0};
    B b{0};
    std::cout << a.a << " " << b.b << std::endl;
}

Идея очень проста: каждый из двух struct предоставляет конструктору один int (который игнорируется). A делегирует его конструктору по умолчанию в списке инициализатора члена (установка a в 42). B пытается сделать то же самое в теле конструктора.

Этот пример компилирует [godbolt] и вызывает правильные конструкторы (A(int) и B(int)), но результат очень отличается:

$ ./a.out
42 17
Конструктор

B по умолчанию никогда не вызывался

Почему это происходит

То, что делает B(int), на самом деле не делегирует конструктор. Вместо этого он создает новый временный объект типа B (точно так же, как вы могли бы сделать B b = B();) и немедленно его отбрасывает. Он ни в коем случае не делегирует ничего.

Единственный способ делегировать конструктор - вызвать его в списке инициализатора члена. Вы также можете делегировать только одному конструктору за раз. [Это не относится к конструкторам базы классы, вызываемые очень похожим образом]

...