- •Введение в понятие класса
- •Void queue::init(void)
- •Перегруженные функции
- •Int sqr_it(int I); // Прототипы
- •Перегрузка операций.
- •Наследование
- •Конструкторы и деструкторы
- •Int sloc,rloc;
- •Void qput(int); // Прототип
- •Int qget(void); // Прототип
- •Конструктор с параметрами
- •Конструктор копирования
- •Void input();
- •Void output();
- •Void ThreeAngle::input()
- •Void ThreeAngle::output()
- •Void main(void)
- •Дружественные функции
- •Замечание
- •Дружественные классы
- •Аргументы функций, задаваемые по умолчанию
- •Void main(void)
- •Void stringxy(char *str, int X, int y)
- •Структуры и классы
- •Объединения и классы
- •Void main()
- •Наследование классов
- •Конструкторы с параметрами при наследовании
- •Множественное наследование
- •Перегрузка функций и операций
- •Ключевое слово this
- •Перегрузка операций ввода/вывода. Инсерторы и экстракторы
- •Void main(void)
- •Vector a(1,2,3),b(4,5,6);
- •Void main(void)
- •Vector a(1,2,3),b(4,5,6);
- •Void main(void)
- •Vector a(1,2,3);
- •Дружественные функции-операции
- •Void main(void)
- •Void swap1(int *I, int *j)
- •Void swap(int a, int b)
- •Void swap1(int *I, int *j)
- •Void swap2(int &a, int &b)
- •Использование ссылочных переменных для перегрузки унарных операций
- •Перегрузка операции индексации [ ]
- •Использование виртуальных функций
- •Указатели на производные типы
- •Виртуальные функции
- •Замечания к использованию виртуальных функций
- •Пример использования виртуальных функций
- •Чистые виртуальные функции и абстрактные типы
- •Производные классы и их конструкторы и деструкторы
- •Void main()
- •Конструкторы и деструкторы при множественном наследовании
- •Void main()
- •Виртуальные базовые классы.
- •Операции динамического выделения памяти new и delete
- •Void main(void)
- •Void main(void)
- •Виртуальные деструкторы
- •Void main(void)
- •Void main(void)
- •Шаблоны классов и функций
- •Шаблоны функций
- •Void main(void)
- •Void main(void)
- •Шаблоны классов
- •Int sloc, rloc;
- •Void qput(t I);
- •Void main(void)
- •Статические члены класса
- •Локальные классы
- •Void f(void);
- •Void main(void)
- •Void f(void)
- •Вложенные классы
- •Void main(void)
Виртуальные деструкторы
При программировании на С++ также типичной является ситуация, когда динамически создается объект производного класса, указатель используется базового класса.
Пример
#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;
};