Необходимо ли конструктору класса Student вызывать конструктор для базового класса Person в списке инициализатора, если да, почему?
Базовый классКонструкторы всегда вызываются перед конструкторами производного класса. Если вы не вызываете их явно в списке инициализации, конструкторы по умолчанию называются неявно .Если базовый класс не имеет конструктора по умолчанию, это не сработает, поэтому вы должны явно указать конструктор базового класса для вызова.
Необходимо вызывать конструкторы базовых классов перед конструкторами производных классов , поскольку вы можете получить доступ к подобъектам базового класса из конструкторов производных классов.Вы можете вызывать их публичные и защищенные функции-члены, и для этого их члены-данные, безусловно, должны быть инициализированы - это то, что делают конструкторы базового класса.
Не могу ли я определить конструктор Student следующим образом -
Student::Student(const string& nm, const string& id, const string& maj, int year)
{
Person(nm, id);
major =maj;
gradYear =year;
}
Нет, вы не можете. Конструкторы базового класса вызываются из списка инициализации перед выполнением тела конструктора производного класса.Именно так определяется язык.
Ваш синтаксис создает неназванный временный объект, который немедленно отбрасывается.
Обратите внимание, что считается хорошим стилем (а для некоторых типов также технической необходимостью) также инициализировать элементы данных в списке инициализации .
Очень веская причина для этого заключается в том, что в C ++ объекты имеют семантику значений , они не являются ссылками.То есть переменная ссылается на фактический объект, а не на ссылку на объект, и назначение между переменными изменяет фактическое содержимое объектов, а не заставляет их ссылаться на другие объекты.
Рассмотрим этот тип:
class Student {
public:
Student(const std::string& n)
{
name = n; // this is bad!
}
// ...
private:
std::string name;
// ...
};
Это назначение name = n
не присваивает ссылки на строки, оно фактически присваивает строки, то есть вызывает оператор присваивания, который затем копирует символы!Чтобы вызвать оператор присваивания names
, name
обязательно должен быть правильно сконструирован.Следовательно, вызов конструктора вставляется компилятором в молчание, поэтому конструктор выглядит следующим образом:
Student(const std::string& n)
: name() // therefore
{
name = n; // this is bad!
}
Теперь это сначала создаст пустую строку, просто чтобы немедленно переопределить ее в следующемзаявление.Это глупо.Поэтому лучше инициализировать все элементы данных (вместе с базовыми классами) в списке инициализации:
Student(const std::string& n)
: name(n) // good!
{
}