Производные классы с конструкторами и деструкторами




 

Каждый класс — базовый и производный может иметь конструктор и де­структор. В каком порядке выполняются эти функции при простом и множе­ственном наследовании? Рассмотрим этот вопрос на модельных примерах.

 

Простое наследование.

Пример 36.

Программа иллюстрирует порядок работы конструктора и деструктора по схеме Base <- Derive1 <- Derive2. Она не делает ничего, кроме создания объектов типа Derive1 и Derive2.

 

#include<iostream.h>

#include<conio.h>

class Base

{ public:

Base () { cout << "Конструктор базового класса Base\n"; }

~Base () { cout << "Деструктор базового класса Base\n"; }

};

class Derive1: public Base

{ public:

Derive1 () { cout << "Конструктор производного класса Derive1\n"; }

~Derive1 () { cout << "Деструктор производного класса Derive1\n"; }

};

class Derive2: public Derive1

{ public:

Derive2 () { cout << "Конструктор производного класса Derive2\n"; }

~Derive2 () { cout << "Деструктор производного класса Derive2\n"; }

};

void main ()

{ clrscr ();

Derive1 d1; cout << endl;

Derive2 d2; cout << endl;

getch();

}

Результаты программы:

Конструктор базового класса Base

Конструктор производного класса Derive1 // объект d1 создан

Конструктор базового класса Base

Конструктор производного класса Derive1

Конструктор производного класса Derive2 // объект d2 создан

 

Деструктор производного класса Derive2

Деструктор производного класса Derive1

Деструктор базового класса Base // объект d2 уничтожен

Деструктор производного класса Derive1

Деструктор базового класса Base // объект d1 уничтожен

 

Комментарии к программе:

Функции-конструкторы выполняются при каждом создании объекта, на­чиная с класса Base — это естественный порядок выполнения. Для создания объекта производного класса необходима инициализация базового класса, так что конструктор должен выполняться.

С другой стороны, деструктор в производном классе должен выполняться раньше выполнения деструктора базового класса. Если деструктор базового класса выполнится раньше, то деструктор производного класса вообще не смо­жет выполниться. Поэтому деструкторы вызываются в порядке, обратном вызо­ву конструкторов.

 

Множественное наследование.

 

В языке С++ производный класс может наследовать от нескольких базо­вых классов. При объявлении производного класса базовые классы перечисля­ются через запятую. Причем при создании объекта конструкторы выполняются в порядке следования базовых классов слева направо.

 

Пример 37.

Программа иллюстрирует порядок работы конструктора и деструктора по схеме множественного наследования: (Base1, Base2) <- Derive. Она не делает ничего, кроме создания объектов типа Base1, Base2, Derive. Рассмотрим мо­дифицированную программу примера 36.

 

#include<iostream.h>

#include<conio.h>

class Base1

{ public:

Base1 () { cout << "Конструктор базового класса Base1\n"; }

~Base1 () { cout << "Деструктор базового класса Base1\n"; }

};

class Base2

{ public:

Base2() { cout << "Конструктор производного класс Base2 \n"; }

~ Base2() { cout << "Деструктор производного класса Base2\n"; }

};

class Derive: public Base1, Base2

{ public:

Derive () { cout << "Конструктор производного класса Derive\n"; }

~Derive () { cout << "Деструктор производного класса Derive\n"; }

};

void main ()

{ clrscr ();

Base1 b1; cout << endl;

Base2 b2; cout << endl;

Derive d; cout << endl;

getch();

}

Результаты программы:

Конструктор базового класса Base1 // объект b1 создан

Конструктор базового класса Base2 // объект b2 создан

Конструктор базового класса Base1

Конструктор базового класса Base2

Конструктор производного класса Derive // объект d создан

 

Деструктор производного класса Derive

Деструктор базового класса Base2

Деструктор базового класса Base1 // объект d уничтожен

Деструктор базового класса Base2 // объект b2 уничтожен

Деструктор базового класса Base1 // объект b1 уничтожен

 

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

 

Виртуальные деструкторы

 

Методы и деструкторы (но не конструкторы!) могут быть виртуальны­ми. Виртуальные деструкторы обычно применяются, когда в некотором классе необходимо удалить объекты производного класса, на которые ссылаются ука­затели на базовый класс. Типичной является ситуация, когда динамически со­здается объект производного класса, а используется указатель на базовый класс.

 

Пример 38.

Рассмотрим простое наследование по схеме Base <- Derive1 <- Derive2. Программа (на основе примера 36) иллюстрирует порядок работы конструкто­ров и деструкторов в классах при динамическом выделении памяти объекту производного класса через указатель на базовый класс и уничтожение объектов с использованием виртуального деструктора. Если объявить деструктор базово­го класса виртуальным, то все деструкторы производных классов также яв­ляются виртуальными.

#include<iostream.h>

#include<conio.h>

class Base

{ public:

Base () { cout << "Конструктор базового класса Base\n"; }

virtual ~Base () { cout << "Деструктор базового класса Base\n"; }

};

class Derive1: public Base

{ public:

Derive1 () { cout << "Конструктор производного класса Derive1\n"; }

~Derive1 () { cout << "Деструктор производного класса Derive1\n"; }

};

class Derive2: public Derive1

{ public:

Derive2 () { cout << "Конструктор производного класса Derive2\n"; }

~Derive2 () { cout << "Деструктор производного класса Derive2\n"; }

};

void main ()

{ clrscr ();

Base *pb = new Derive2; // выделение памяти объекту Derive2

if (! pb)

{ cout << "Недостаточно памяти\n";

return 1; // аварийное окончание программы

}

cout << endl;

delete pb; // вызов всех деструкторов производных и базового классов

return 0;

}

Результаты программы:

Конструктор базового класса Base

Конструктор производного класса Derive1

Конструктор производного класса Derive2 // создание объекта типа Derive2

 

Деструктор производного класса Derive2

Деструктор производного класса Derive1

Деструктор базового класса Base // уничтожение объекта типа Derive2

 

Комментарии к программе:

При разрушении объекта с помощью операции delete через указатель на базовый класс были корректно вызваны деструкторы всех классов в нужном по­рядке. Если бы деструктор базового класса не был объявлен виртуальным, то вызывался бы только деструктор базового класса (проверьте это). Динамиче­ская память, выделенная объекту конструктором, при разрушении объекта обычным деструктором не освобождалась бы корректно.

 

Пример 39.

Рассмотрим модифицированную программу на основе примеров 33 и 35, в которой используется абстрактный базовый класс Figure с чистой виртуальной функцией show_area() и виртуальным деструктором. Базовый класс Figure описывает плоскую фигуру с двумя измерениями, которые задаются конструк­тором со вторым параметром по умолчанию. Нельзя создать объект данного класса, но можно определить указатель на тип класса. От этого класса на осно­ве расширяющегося наследованиия строятся производные классы по схеме: Figure <- (Triangle, Rectangle, Circle). В производных классах определены свои функции show_area().

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

 

#include<iostream.h>

#include<conio.h>

class Figure // абстрактный базовый класс

{ protected: // защищенные элементы, доступные в производных классах

double x, y;

public:

Figure (double i, double j=0) // конструктор с параметром по умолчанию

{ x = i, y = j; // задание измерений фигур

cout<<"Конструктор базового класса Figure\n";

}

virtual void show_area() = 0; // чистая виртуальная функция

virtual ~Figure () // виртуальный деструктор Figure { cout<<"Деструктор базового класса Figure\n";}

};

class Triangle: public Figure // производный класс Triangle

{ public:

Triangle (double i, double j): Figure (i, j) // конструктор Triangle

{ cout<<"Конструктор Triangle\n"; }

void show_area() // виртуальная функция Triangle

{ cout<<"Треугольник с высотой "<< x <<" и основанием "<< y;

cout<<" имеет площадь = "<< x*0.5*y <<endl;

}

~Triangle() // виртуальный деструктор Triangle

{ cout<<"Деструктор классаTriangle \n";}

};

class Rectangle: public Figure // производный класс Rectangle

{ public:

Rectangle (double i, double j): Figure (i, j) // конструктор Rectangle

{ cout<<"Конструктор Rectangle\n"; }

void show_area() // виртуальная функция Rectangle

{ cout<<"Прямогольник со сторонами "<< x <<" и "<< y;

cout<<" имеет площадь = "<< x*y <<endl;

}

~Rectangle() // виртуальный деструктор Rectangle { cout<<"Деструктор класса Rectangle\n"; }

};

class Circle: public Figure // производный класс Circle

{ public:

Circle (double i): Figure (i) // конструктор Circle {cout<<"Конструктор Circle\n"; }

void show_area() // виртуальная функция Circle

{ cout<<"Круг с радиусом "<< x;

cout << " имеет площадь = " << 3.14*x*x << endl;

}

~Circle() // виртуальный деструктор Circle { cout<<"Деструктор класса Circle\n"; }

};

void main ()

{ clrscr();

cout << "Работа программы:\n";

Figure *p; // объявление указателя класса Figure

Triangle t (3,4); // создание объекта класса Triangle

Rectangle r (5,6); // создание объекта класса Rectangle

Circle c (2); // создание объекта класса Circle

p = &t; // базовый указатель на объект типа Triangle

p -> show_area(); // вывод сообщения о площади объекта типа Triangle

p = &r; // базовый указатель на объект типа Rectangle

p -> show_area(); // вывод сообщения о площади объекта типа Rectangle

p = &c; // базовый указатель на объект типа Circle

p -> show_area(); // вывод сообщения о площади объекта типа Circle

}

Результаты программы:

Работа программы:

Конструктор базового класса Figure

Конструктор Triangle

Конструктор базового класса Figure

Конструктор Rectangle

Конструктор базового класса Figure

Конструктор Circle

Треугольник с высотой 3 и основанием 4 имеет площадь = 6

Прямогольник со сторонами 5 и 6 имеет площадь = 30

Круг с радиусом 2 имеет площадь = 12.56

Деструктор класса Circle

Деструктор базового класса Figure

Деструктор класса Rectangle

Деструктор базового класса Figure

Деструктор классаTriangle

Деструктор базового класса Figure

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2018-01-08 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: