#c #inheritance #constructor
#c #наследование #constructor
Вопрос:
class A : public B
{
...
}
// case I : explicitly call the base class default constructor
A::A() : B()
{
...
}
// case II : don't call the base class default constructor
A::A() // : B()
{
...
}
Равен ли случай II случаю I?
Что касается меня, я предполагаю, что конструктор базового класса B по умолчанию НЕ вызывается в случае II. Однако, несмотря на то, что я все еще придерживаюсь этого предположения, я запустил тест, который доказывает обратное:
class B
{
public:
B()
{
cout << "B constructor" << endl;
}
};
class A : public B
{
public:
A()
{
cout << "A constructor" << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
return 0;
}
// вывод из VS2008
B constructor
A constructor
Press any key to continue . . .
Ответ №1:
Конструктор базового класса вызывается в обоих случаях.
Вот ссылка на статью с дополнительной информацией.
Ответ №2:
Если у B
нет пользовательского объявленного конструктора, поведение отличается. Сравнить:
struct SimpleAggregate {
int a;
float b;
};
struct ClassWrapper : SimpleAggregate {
ClassWrapper() : SimpleAggregate() { }
};
ClassWrapper w;
Теперь, w.a
и w.b
гарантированно равны нулю. Если бы вы отказались от явной инициализации базового класса, они имели бы неопределенные значения.
Возможно, вам неизвестно, что, несмотря на синтаксис, приведенное выше использование SimpleAggregate()
не вызывает конструктор по умолчанию. Это просто значение инициализирует базовый класс (у нас есть несколько хороших ответов здесь, в Stackoverflow, о том, что такое «инициализация значения»), не вызывая конструктор по умолчанию, потому что пользователь не объявлен.
Комментарии:
1. Это такая большая разница. Это должно быть принято в качестве ответа.
Ответ №3:
Если конструктор базового класса не принимает никаких аргументов, то явное упоминание о нем в списке инициализации не требуется.
Ответ №4:
Чтобы завершить процесс обучения и развить более глубокое понимание, вы могли бы начать немного изменять вещи. Например, что происходит, когда у B
нет конструктора по умолчанию? Он вообще компилируется? Другие небольшие модификации, подобные этой, обеспечат отличный опыт обучения.
Тем не менее, по моему опыту, обычно лучше делать это
A::A() : B() { ... }
чем
A::A() { ... }
потому что первый вариант более явный, и он заставит вас задуматься о том, что на самом деле происходит с инициализацией базового класса. Вероятно, вы избежите скрытого поведения, описав вещи явно.
Комментарии:
1. Я поставил вам плюс один, потому что вы предложили способы улучшить понимание этой темы.
2. Я указал 1, потому что это отвечает на вопрос «должен …». Большинство других ответов относятся к соответствующему вопросу «должен …».
Ответ №5:
Каждый класс, производный от какого-либо другого класса, должен вызывать конструктор базового класса. Производный класс может быть создан только после того, как все базовые классы ‘ будут полностью сконструированы. Таким образом, не имеет значения, вызываете ли вы конструктор базового класса или нет. Если вы не вызовете, пока существует конструктор по умолчанию, доступный для определения компилятором, он будет вызван. В противном случае компилятор выдаст ошибку.