2015-05-19 3 views
4

У меня вопрос о неявных и явных вызовах базового конструктора. Если мы имеем иерархию классов, как это:C++ неявный и явный вызов конструктора наследования

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 ;} 

}; 

По моим конспектам, призыв к «Baby» в главном, например, так:

std::string babyname = "Robert"; 
int nappies = 5; 

Baby baby(babyname, nappies); 

Причин следующего случаться:

  1. в качестве явного вызова лица производится в списке инициализации ребенка: список инициализации младенца получает называется и no_of_nappies инициализируется.
  2. Далее выполняется вызов конструктора Person и вызывается список инициализации человека. . Инициализируется m_name.
  3. Затем вызывается тело конструктора человека.
  4. Корпус конструктора младенца, наконец, называется.

Это имеет смысл, однако, что о если бы неявные вызовы, сделанные в конструктор по умолчанию родительского класса, например:

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; в основном имеет следующий эффект:

  1. неявный вызов к конструктору по умолчанию автомобиля от велосипеда. Прежде чем вызывать список инициализации велосипеда.
  2. Как автомобиль не унаследовать от чего-либо, списка инициализации автомобильного называются, где он инициализирует m_no_wheels к 0.
  3. Корпус конструктора транспортного средства называется.
  4. Вернемся к Bicycle и теперь его список инициализации называется, инициализацией m_is_locked к false.
  5. Тело конструктора велосипеда называется.

Не мог бы кто-нибудь объяснить, верно ли мое обоснование скрытого вызова?

Основное отличие, на мой взгляд, состоит в том, что при явной ссылке на базовый конструктор список инициализации дочернего класса всегда попадает первым, чтобы вызвать этот базовый конструктор, однако с неявным вызовом, список инициализации верхнего большинства родителей всегда попадает в первую очередь.

Спасибо, и очень ценим!

Редактировать: Я спрашиваю конкретно, изменился ли заказ, в зависимости от неявного или явного вызова родительского класса.

ответ

3

Порядок инициализации база и членов определяются в [class.base.init]/11, и вы можете найти краткое описание здесь: http://en.cppreference.com/w/cpp/language/initializer_list#Initialization_order

Порядок инициализаторов членов в списке не имеет значения: фактический порядок инициализации выглядит следующим образом:

  1. Если конструктор для наиболее производного класса, классы виртуальных базовых инициализируются в том порядке, в котором они появляются в глубине первой слева направо обход объявления базового класса (слева направо относится к появлению в списках базового спецификатора)
  2. Затем прямые базовые классы инициализируются в порядке слева направо, как они появляются в списке базового спецификатора этого класса
  3. Затем нестатические элементы данных инициализируются в порядке объявления в определении класса.
  4. Наконец, тело конструктора выполняется

(Примечание: если порядок инициализации контролировалась появлением в член инициализатора списки различных конструкторов, то деструктор не сможет гарантировать, что порядок уничтожения является обратным порядку строительства)

Порядок инициализации установлен на камне до того, как будут определены любые конструкторы; список инициализатора конструктора влияет только на , так как инициализируются базы и элементы, а не порядок их инициализации.

Поскольку Person является базой Baby, он всегда инициализируется перед тем членом Baby «s m_no_of_nappies. Как часть инициализации Person, его собственные элементы инициализируются, а затем выполняется его тело конструктора. После того, как тело конструктора Person вернется, то инициализируется m_no_of_nappies. (Уничтожение всегда происходит в обратном порядке.) Vehicle также является базой Bicycle и инициализируется первым; поскольку для него не существует mem-initializer, вызывается конструктор по умолчанию.

+0

Это имеет большой смысл. Просто уточнить: означает ли это, что даже если инициализатор и конструктор 'Person' вызывается до запуска' m_no_of_nappies' - список инициализации «Baby» по-прежнему попадает, чтобы вызвать инициатор Person. Итак, 'Baby' называет человека из его списка инициализации, поэтому первое, что попало, это список инициализации« Baby »? –

+0

@MuyiwaOlu Я не уверен, что понимаю ваш вопрос. Я не знаю, что вы подразумеваете под «хитом». Базы и элементы инициализируются в установленном порядке, и во время этой инициализации, если имеется соответствующий mem-инициализатор, он используется для инициализации именованной базы или члена. – Brian

+0

@MuyiwaOlu Если вы не указали конструктор базового класса перед списком инициализации данных производного класса, вы можете получить предупреждение, зависящее от настроек компилятора. – Steephen

1

§12.6.2 определяет, как все инициализируются:

Порядок инициализаторах членов в списке не имеет значения: фактическая порядок инициализации выглядит следующим образом:

  • Если конструктор для наиболее производный класс, виртуальные базовые классы инициализируются в том порядке, в котором они отображаются в глубине-первом обход слева-направо объявлений базового класса (слева направо refe RS к появлению в списках базовых спецификаторов)
  • Тогда, прямой базовую классов инициализируются в левом направо порядке, как они появляются в списке базовых спецификатора этого класса
  • Затем, не статические данные являются инициализируется в порядке объявления в определении класса.
  • Наконец, тела конструктора выполняется (Примечание: если порядок инициализации контролировались появлением в члене инициализатора списки различных конструкторов, то деструктор не сможет обеспечить , что порядок разрушение является обратным порядком строительства)

Обобщенная для вашего случая (и, оставляя в стороне виртуальные функции):

  1. Базовые классы в порядке наследования объявленного
  2. Члены в порядке объявления

Таким образом порядок в списке Конструктор инициализатора не имеет никакого эффекта.

В первом случае вы не правы в этом пункте: Person является базовым классом Baby и инициализируется перед тем m_no_of_nappies


Edit: Ваш вопрос

Детские звонки Человек из в его списке инициализации, следовательно, первое, что попало, это список инициализации Baby's?

[class.base.init]/10, вероятно, что вы ищете: вы на самом деле не «называют» конструктор базового класса (при условии, что нет ни одной делегации), она вызывается компилятор для вас при инициализации производного объекта.

компилятор устанавливает вещи для вас, чтобы помочь поддержанию порядка конструкторов и деструкторов правых

Причина игнорирования порядка инициализаторах является сохранение обычного FIFO порядок вызовов конструктора и деструктора. Разрешение двух конструкторов использовать разные порядки инициализации база и членов будет сдерживать реализацию использовать более динамичные и более дорогие стратегии

Взятых из https://stackoverflow.com/a/24287946/1938163

И наконец

является неявным вызовом базовый класс (который делает компилятор), сделанный до списка инициализации велосипеда или после?

Перед остальными инициализациями классов членов, как в §12.6.2.

+0

Спасибо, что ухаживал за этим. Как насчет второго, неявного вопроса? –

+0

@MuyiwaOlu * [class.base.init]/10 *, вероятно, вы ищете. Вы действительно не «вызываете» конструктор базового класса (предполагая, что нет делегирования), он вызывается компилятором для вас при инициализации производного объекта. –

+0

Я просто хотел узнать, неявный вызов базового класса (что компилятор делает) было сделано до списка инициализации «Велосипеда» или после? –

Смежные вопросы