Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
С++ - ООП.doc
Скачиваний:
11
Добавлен:
21.09.2019
Размер:
399.87 Кб
Скачать

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

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

Пример

#include <iostream.h>

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

class Base {

public:

Base() { cout<<”\n Конструктор класса Base\n”; }

~Base() { cout<<”\n Деструктор класса Base\n”; }

};

class Derive1:public Base {

public:

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

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

};

class Derive2:public Derive1 {

public:

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

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

};

Void main(void)

{

Base *pb=new Derive2;

if(!pb)

{

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

return 1;

}

cout<<endl;

delete pb;

}

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

Конструктор класса Base

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

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

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

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

Пример:

#include <iostream.h>

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

class Base {

public:

Base() { cout<<”\n Конструктор класса Base\n”; }

virtual ~Base() { cout<<”\n Деструктор класса Base\n”; }

};

class Derive1:public Base {

public:

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

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

};

class Derive2:public Derive1 {

public:

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

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

};

Void main(void)

{

Base *pb=new Derive2;

if(!pb)

{

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

return 1;

}

cout<<endl;

delete pb;

}

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

Конструктор класса Base

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

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

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

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

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

Шаблоны классов и функций

В языке С++ предусмотрена еще одна реализация полиморфизма – шаблоны функций (Function Templates) и шаблоны классов (Class Templates).

Шаблоны функций

При перегрузке функций рассматривали семейство функций sqr_it() с различными типами аргументов. Эти функции возвращали квадрат аргумента и тип возвращаемого значения совпадал с типом аргумента. Для каждого типа описывалось свое тело функции, причем отличались функции только типом аргумента и типом возвращаемого значения. Шаблоны функций позволяют использовать в качестве аргумента тип переменной.

template <class T>

T sqr_it(T x)

{ return x*x; }

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

Пример:

#include <iostream.h>

template <class T>

T sqr_it(T x)

{

return x*x;

};