MyTetra Share
Делитесь знаниями!
Наливные полы полимерный www.stroipol.com/uslugi/ustrojstvo-polov/polimernye-poly.
Объявления аренда офисов в екатеринбурге http://mbc66.ru/.
Как срабатывают конструкторы, деструкторы и инициализация переменных в C++
17.01.2016
12:37
Автор: Xintrea
Текстовые метки: c++, конструктор, деструктор, инициализация, класс, объект, наследование, последовательность
Раздел: Компьютер - Программирование - Язык C++

Следующий пример кода демонстрирует последовательность выполнения действий при создании (инициализации класса, вызова конструктора и деструктора.


Сначала пример:


#include <iostream>

 

using namespace std;

 

// Базовый класс

class Base

{

  public:

    Base() { cout << "Base::constructor()" << endl; }

    virtual ~Base() { cout << "Base::destructor()" << endl; }

    virtual void print() = 0;

};

 

// Производный класс

class Derived: public Base

{

  public:

    Derived() { cout << "Derived::constructor()" << endl; }

   ~Derived() { cout << "Derived::destructor()" << endl; }   

    void print() {}  

    Object  obj;

};



// Вспомогательный класс, объект которого используется в производном классе

class Object 

{

  public:

    Object() { cout << "Object::constructor()" << endl; }

   ~Object() { cout << "Object::destructor()" << endl; }

};


// Основная функция

int main ()

{

    Derived *p = new Derived;

    delete p;

    return 0;

}


На всякий случай надо обратить внимание, что перегружаемые в производном классе методы - деструктор и метод print() - в базовом классе должны быть объявлены как virtual. Если не обозначит как virtual деструктор базового класса, тогда не будет происходить вызова деструктора производного класса при разрушении объекта производного класса. Если не обозначить как виртуальный метод print(), то компилятор будет ругаться что перегружается не виртуальный метод.


В программе создается один экземпляр производного класса
Derived.



Последовательность создания объекта


1. Создание объекта производного класса Derived начинается с инициализации свойств базового класса Base (этап 1) и запуска конструктора базового класса Base (этап 2). Никаких свойств у базового класса нет, поэтому этап 1 нам будет невиден. На экране появится:


Base::constructor()


2. Далее происходит инициализация свойств и запуск конструктора производного класса Derived. У производного класса Derived есть свойство obj. Как было сказано выше, будет запущен этап 1 - инициализация объекта obj. Инициализация объекта obj состоит все из тех же двух этапов - инициализация свойств и запуск конструктора. Свойств у класса Object нет, поэтому этап 1 мы не видим. Происходит запуск конструктора объекта obj. На экране мы увидим:


Object::constructor()


То есть, когда класс Derived включает в себя объект другого класса Object, вначале происходит создание объекта включаемого класса Object, и только потом создается объект Derived.


3. Инициализация свойств производного класса Derived описана в пункте 2. Теперь настает время второго этапа - т. е. запуска конструктора Derived. На экране мы увидим:


Derived::constructor()


Объект Derived создан. Он унаследован от класса Base, и содержит экземпляр класса Object в одном из своих полей.



Последовательность удаления объектов


Последовательность удаления объектов будет обратна последовательности создания структуры объектов:


Derived::destructor()

Object::destructor()

Base::destructor()



Бонус: трюки C++ при создании объекта


Программисты C++ очень любят неочевидные конструкции. Почему-то считается хорошим тоном использовать побочные эффекты в выражениях, заворачивать код в короткие, но плохо читаемые конструкции, писать условия с перестановкой естественных lvalue и rvalue задом-наперед, и использовать прочие прелести C++.


Опытный C++ программист обязательно воспользуется одним из свойств динамического полиморфизма - а именно возможностью доступа к объекту производного класса по указателю на базовый класс. И даже в строке создания объекта класса Derived он не напишет естественное:


Derived *p = new Derived;


Он напишет вот так:


Base *p = new Derived;


Какой в этом смысл - не совсем понятно. Возможно, таким образом упрощается вся структура программы: вместо точного указания типа класса везде используется просто тип базового класса. Но однозначного подтверждения этой мысли у меня нет, поэтому вопрос "зачем так делать?" остается открытым.



Так же в этом разделе:
← Содержание ...
 
MyTetra Share v.0.35
Яндекс индекс цитирования