Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Деструкторы при наследовании
- Явно вызывать деструкторы не надо.
- Если в конструкторе дочернего класса выделялась память под специфические поля, эту память нужно освободить в деструкторе производного класса. Чтобы деструктор родительского класса вызывался автоматически перед прототипом деструктора нужно писать virtual.
- virtual прототип_деструктора
- Динамический полиморфизм
- Классы могут иметь одноименные методы(это также касается классов, являющихся членами наследственной иерархии)
- При этом начинка методов может быть совершенно разной -> разная реализация
- Создается объект род. класса, потом выделяется память под спец.поля.
- Указатель на объект предка является одновременно указателем на объекты любых его наследников.
- Таким образом, через указатель на объект базового класса можно обеспечить создание объектов любого из классов-наследников.
- Пример 1.
- class TPar
- {
- int x;
- public:
- TPar(int xx=1);
- void pvvod(); //Mетод 1
- void fff(int a); //2
- };
- TPar::TPar(int xx)
- {
- x=xx;
- }
- void TPar::pvvod()
- {
- cout << "Vv. X" << endl;
- cin >> x;
- }
- void TPar::fff(int a)
- {
- x*=a;
- }
- class TChl:public TPar
- {
- int y;
- public:
- TChl(int xx=1, int yy=2);
- void cvvod(); //Mетод 3
- void fff(int a); //Mетод 4
- };
- TChl::TChl(int xx, int yy):TPar(xx)
- {
- y=yy;
- }
- void TChl::cvvod()
- {
- pvvod();
- cout << "Vv. Y" << endl;
- cin >> y;
- }
- void TChl::fff(int a)
- {
- for(int i = 1; i <= a; i++)
- {
- x+=y;
- }
- }
- void main()
- {
- TPar *p1,*p2;
- TChl *c1,*c2;
- p1 = new TPar; //Создание объекта родительского класса
- p2 = new TChl; //Создается объект дочернего класса
- с1 = new TPar; //Ошибка
- с2 = new TChl; //Создается объект дочернего класса
- p1 -> pvvod(); //1
- p1 -> fff(5); //2
- c2 -> pvvod(); //1
- c2 -> fff(27); //4
- c2 -> TPar::fff(19); //2
- c2 -> cvvod(); //3
- p2 -> pvvod(); //1
- p2 -> fff(7); //2 (потому что объявлено как TPar *p2)
- p2 -> cvvod(); //Ошибка
- p2 -> TChl::fff(3); //Ошибка
- Чтобы обратиться к собственным методам дочернего класса в данном случае нужно выполнить явное преобразование типа указателя р2 к типу (TChl*)
- ((TChl*)p2) - > cvvod(); //3
- ((TChl*)p2) - > fff(3); //4
- }
- +В ходе работы программы можно выбирать нужный объект из родственной иерархии, соответствующим образом, выделяя память.
- -Указатель на объект не знает с объектом какого класса он связан, для того чтобы получить доступ к собственным методов классов - наследников нужно выполнять явное преобразование типа, что сводит на нет позитивное.
- Для решения этой проблемы в с++ имеется инструмент - виртуальные функции.
- Особенности виртуальных функций.
- 1) Функции должны быть одноименными и кроме того иметь полностью совпадающие сигнатуры(возвращаемое значение и список параметров)
- Не следует путать это с перегрузкой функций, при перегрузке список параметров должен различаться.
- 2) Виртуальные функции должны быть членами классов.
- 3) Виртуальность передается по наследству, какой бы длинной не была цепочка наследников.
- 4) Если определение виртуальной функции отстутствует в середине цепочки, то виртальность сохраняется, а работать будет предыдущая реализация.
- (1) - Есть, работает (1)
- (2) - Нет, работает (1)
- (3) - Есть, работает (3)
- Пример 2.
- (TA)
- \
- (TB)
- \
- (TC)
- class TA
- {
- int x;
- public:
- TA(int xx=1);
- virtual void fff();
- .... //виртуальных методов 100 штук
- };
- //Реализация
- class TB:public TA
- {
- int y;
- public:
- TB(int xx=1, int yy=2);
- void fff(); //Виртуальность передается по наследству
- ... // 100 штук
- };
- //Реализация
- class TC:public TB
- {
- int z;
- public:
- TC(int xx = 1, int yy = 2, int zz = 3);
- void fff();
- ... // 100 штук
- };
- //Реализация
- void main()
- {
- TA* uk;
- int n;
- do
- {
- cout << " 1 - объект TA, 2 - объект TB, 3 - объект TC;
- cin >> nl
- }
- while(n < 1 || n > 3);
- switch (n)
- {
- case 1:
- uk = new TA; break;
- case 2:
- uk = new TB; break;
- case 3:
- uk = new TC; break;
- }
- uk - > fff();
- ...//все 100 виртуальных методов
- delete uk;
- }
- Виртуальных конструкторов быть не может.
- Достаточно часто в базовом классе виртуальный метод не имеет собственной осмысленной реализации.
- Пример:
- геометрическая фигура
- базовый класс - фигура
- от этого класса наследуем прямоугольник/трапеция/окружность..........
- В таком случае виртуальный метод делают чисто виртуальным.
- Класс который содержит хотя бы 1 чисто виртуальный метод - абстрактный.
- Особенно чисто виртуальных функций и абстрактных классов:
- 1)Прописывать реализацию чисто виртуального метода не надо
- 2)Нельзя создавать объекты абстрактных классов, они используются только для того, чтобы от них что-то наследовалось
- 3)Чистая виртуальность передается по наследству, пока функция не получит реализацию, после этого она становится виртуальной
- Чисто виртуальная : virtual прототип_деструктора = 0
- Пример 3:
- Окрашенная фигура на плоскости.
- Фигура
- / | \
- Прямоугольник Круг Трапеция
- class TFig
- {
- int color;
- public:
- TFig(int c=0)
- virtual float sq() = 0;
- };
- TFig::TFig(int c)
- {
- color = c;
- }
- //
- class TPr:public TFig
- {
- float a, b; //ширина + высота
- public:
- TPr(int c = 0, float a = 1, float b = 2);
- float sq();
- };
- //Реализация конструктора
- float TPr()
- {
- return a*b;
- }
- Также для классов круг и трапеция.
- class TCirc:public TFig
- class TTr:public TFig
- Точно также как в примере 2 можно организовать меню для выбора фигуры, в операторе switch будет выделяться память под прямоугольник,
- круг или трапецию, далее будет выполнятсья метод вычисления площади + другие методы, если бы они были
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement