В чем разница между делегированием конструкторов в списке инициализатора члена и в теле конструкторов
Конструкторы из C++11 позволяют нам создавать цепочки конструкторов. Например, мы можем закодировать это:
Class Foo
{
public:
Foo()
{
}
Foo(int n): Foo()
{
}
};
Я попытался делегировать Foo() как в списке инициализации члена, так и в теле кода. Я получаю одинаковые возвращаемые значения в обеих ситуациях. У меня вопрос, есть ли на самом деле какие-либо различия в обоих методах? Если они одинаковы, есть ли преимущество перед применением одного над другим?
1 ответ
[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
S выставляет конструктор, принимающий один int
(это игнорируется). A
делегирует его конструктору по умолчанию в списке инициализатора члена (настройка a
до 42). B
пытается сделать то же самое в теле конструктора.
Этот пример компилирует [godbolt] и вызывает правильные конструкторы (A(int)
а также B(int)
), но результат очень отличается
$ ./a.out
42 17
B
конструктор по умолчанию никогда не вызывался
Почему это происходит
Какие B(int)
действительно не делегирует конструктор. Вместо этого он создает новый временный объект типа B
(так же, как вы могли бы сделать B b = B();
) и сразу же отбрасывает его. Это не делегирует ничего в любом случае.
Единственный способ делегировать конструктор - вызвать его в списке инициализатора члена. Вы также можете делегировать только одному конструктору за раз. [Это не относится к конструкторам базовых классов, вызываемых очень похожим образом]