У меня есть вопрос о неявных и явных вызовах базового конструктора. Если у нас есть иерархия классов, как это:
class Person{
protected:
std::string m_name;
public:
Person(std::string& _name) : m_name(_name){std::cout << "A person is being constructed." << std::endl;}
};
class Baby : public Person{
private:
int m_no_of_nappies;
public:
Baby(std::string& _name, int& _no_of_nappies) : m_no_of_nappies(_no_of_nappies), Person(_name) {std::cout << "A baby is being constructed." << std::endl ;}
};
Согласно моим конспектам, звонок на «Малышку» в основном такой:
std::string babyname = "Robert";
int nappies = 5;
Baby baby(babyname, nappies);
Вызывает следующее:
no_of_nappies
инициализируется.m_name
инициализируется.Это имеет смысл, однако, что, если бы были неявные обращения к конструктору по умолчанию родительского класса, например так:
class Vehicle{
protected:
int m_no_wheels;
public:
Vehicle() : m_no_wheels(0) { std::cout << "A vehicle is being constructed." << std::endl; }
};
class Bicycle : public Vehicle{
protected:
bool m_is_locked;
public:
Bicycle() : m_is_locked(false) { std::cout << "A bicycle is being constructed." << std::endl; }
};
Это та часть, в которой я не уверен. Мое лучшее предположение, что звонок Bicycle bike;
В основном имеет следующий эффект:
m_no_wheels
в 0
,m_is_locked
в false
,Может ли кто-нибудь объяснить, правильны ли мои аргументы в пользу неявного вызова?
Основное отличие, на мой взгляд, заключается в том, что при явной ссылке на базовый конструктор список инициализации дочернего класса всегда вызывается первым, чтобы вызвать этот базовый конструктор — однако при неявном вызове самый верхний родительский класс список инициализации всегда выполняется первым.
Спасибо и высоко ценится!
Редактировать: Я спрашиваю конкретно, если порядок меняется, в зависимости от неявного или явного вызова родительского класса.
Порядок инициализации баз и членов указан в [class.base.init] / 11, и вы можете найти резюме здесь: http://en.cppreference.com/w/cpp/language/initializer_list#Initialization_order
Порядок инициализаторов элементов в списке не имеет значения: фактический порядок инициализации следующий:
- Если конструктор предназначен для самого производного класса, виртуальные базовые классы инициализируются в том порядке, в котором они появляются при обходе слева направо в объявлениях базового класса в глубину (слева направо относится к появлению в base списки спецификаторов)
- Затем прямые базовые классы инициализируются в порядке слева направо по мере их появления в списке базовых спецификаторов этого класса.
- Затем нестатические члены-данные инициализируются в порядке объявления в определении класса.
- Наконец, тело конструктора выполняется
(Примечание: если порядок инициализации контролировался появлением в списках инициализаторов элементов различных конструкторов, то деструктор не сможет гарантировать, что порядок уничтожения является обратным порядку построения)
Порядок инициализации устанавливается в камне до того, как были определены какие-либо конструкторы; список инициализатора конструктора влияет только как базы и члены инициализируются, а не порядок, в котором они инициализируются.
Так как Person
является основой Baby
всегда инициализируется раньше Baby
член m_no_of_nappies
, В рамках инициализации Person
, его собственные члены инициализируются, а затем выполняется его тело конструктора. После Person
тело конструктора возвращается, то m_no_of_nappies
инициализируется. (Разрушение всегда происходит в обратном порядке.) Vehicle
также основа Bicycle
и инициализируется первым; так как нет мем-инициализатор для этого вызывается конструктор по умолчанию.
§12.6.2 определяет, как вещи инициализируются:
Порядок инициализаторов членов в списке не имеет значения: фактический
порядок инициализации следующий:
- Если конструктор предназначен для самого производного класса, виртуальные базовые классы
инициализируются в том порядке, в котором они появляются по глубине
обход слева направо объявлений базового класса (слева направо
относится к появлению в списках базовых спецификаторов)- Тогда прямая база
классы инициализируются в порядке слева направо, как они появляются в этом
список базовых спецификаторов класса- Тогда нестатические члены данных
инициализируется в порядке объявления в определении класса.- В заключение,
тело конструктора выполняется (Примечание: если порядок инициализации
контролировалось появлением в списках инициализатора членов
различные конструкторы, то деструктор не сможет обеспечить
что порядок уничтожения является обратным порядку
строительство)
Подведем итог для вашего случая (и оставив в стороне виртуальные функции):
таким образом порядок в списке инициализатора конструктора не влияет.
В первом случае вы ошибаетесь в этом пункте: Person
это базовый класс Baby
и инициализируется раньше m_no_of_nappies
Редактировать:
Ваш вопрос
Baby вызывает Person из своего списка инициализации, поэтому первое, что бросается в глаза, это список инициализации Baby?
[Class.base.init] / 10 Вероятно, это то, что вы ищете: вы на самом деле не «вызываете» конструктор базового класса (при условии, что нет делегирования), он вызывается компилятором для вас при инициализации производного объекта.
Компилятор настраивает вещи для вас, чтобы помочь поддерживать порядок конструкторов и деструкторов правильно
Причиной игнорирования порядка инициализаторов является сохранение обычного порядка FIFO вызовов конструктора и деструктора. Разрешение двум конструкторам использовать разные порядки инициализации баз и членов ограничило бы реализации использованием более динамичных и более дорогих стратегий.
Взято из https://stackoverflow.com/a/24287946/1938163
И наконец
выполняется неявный вызов базового класса (который выполняет компилятор) до списка инициализации Bicycle или после?
Перед остальной частью инициализации класса члена как в §12.6.2.