Обратите внимание, что в C ++ «инициализация» (создание объекта определенным образом, например, std::string str = "hi";
) и «присваивание» (изменение значения существующего объекта, например, str = "hi";
) - это две разные вещи.
Когда вы пишете конструктор, как
Car::Car(double s)
{
m_Speed = s;
}
C ++ нуждается в объекте, и все его члены существуют, и поэтому уже инициализированы к тому времени, как вы достигнете первого {
. Оператор m_Speed = s;
является присваиванием, а не инициализацией. Так как вы не указали, как m_Speed
должен быть инициализирован, C ++ вставляет логику для «инициализации по умолчанию» перед началом конструктора (хотя для базового типа, такого как double
, это просто означает, что оно имеет неопределенное значение до назначения ).
Обычно это не имеет значения для члена типа double
. Но это может быть для члена типа класса, и это определенно подходит для члена ссылочного типа: ссылка ДОЛЖНА быть инициализирована, потому что ссылка всегда должна ссылаться на некоторый объект, а присвоение, левая часть которого всегда является ссылочной переменной, всегда назначает этому указанному объекту; нет способа изменить объект, на который ссылается ссылка.
Способ указать, как конструктор инициализирует элементы, использует список инициализаторов элементов:
Car::Car(double s)
: m_Speed(s)
{}
Race::Race(const Car& c, Track t)
: m_Car(c), m_Track(t)
{
m_Car.Show();
}
Использование списков инициализаторов членов всегда, когда это возможно, хорошая привычка, но здесь вы столкнулись с одним случаем, когда это абсолютно необходимо.
[Примечание 1: показанный выше конструктор Race
все равно не будет работать из-за другой проблемы: вы не можете инициализировать ссылку Car&
из const Car&
. Вам нужно будет либо изменить конструктор, чтобы он принимал не const
параметр, либо изменить член на тип const Car&
. Не const
параметр также позволит избежать потенциальных проблем с привязкой к временному.]
[Примечание 2: Другой способ указать инициализатор для членов класса - поставить = something;
после объявления члена в классе. Этот инициализатор по умолчанию будет использоваться, когда конструктор не указывает инициализатор для этого члена и в неявно определенном конструкторе по умолчанию, если таковой имеется. Это может быть удобно, если вы хотите, чтобы несколько конструкторов использовали один и тот же инициализатор.]