Similar presentations:
Лекция 7 Виртуальные классы и методы
1. Виртуальные классы и виртуальные функции. Динамический полиморфизм
Васильева Лидия Николаевнадоцент кафедры автоматики и управления
в технических системах
2. Иерархия классов
В этом случае класс Базовый фактическинаследуется классом Производный_3 дважды —
первый раз через класс Производный_1, а
второй через Производный_2. Если член класса
Базовый будет использоваться в классе
Производный_3, это вызовет неоднозначность.
3. Виртуальный базовый класс
Для преодоления этой неоднозначности в C++включен механизм, благодаря которому в классе
Производный_3 будет включена только одна копия
класса Базовый.
Класс, поддерживающий этот механизм, называется
виртуальным классом.
Чтобы сделать класс виртуальным нужно перед
спецификатором доступа использовать ключевое
слово virtual.
4. Пример. Виртуальный базовый класс
#include <iostream>using namespace std;
class B {
public:
int i;
};
class D1: virtual public B {
public:
int j;
};
class D2: virtual public B {
public:
int k;
};
5. Продолжение программы
class D3: public D1, public D2 {public:
int pr() { return i * j * k; }
};
int main()
{D3 ob;
ob.i = 1;
ob.j = 3 ;
ob.k = 5;
cout << "Rezultat= " << ob.pr()<<endl;
return 0;
}
6. Виртуальные методы
Виртуальный метод объявляется внутри базового класса ипереопределяется в производном.
Перед объявлением метода ставится virtual.
Каждое переопределение виртуального метода связано со
спецификой производного класса.
При переопределении ключевое слово virtual больше не
требуется.
Чтобы явным образом указать, что метод переопределяется, в
производном классе после списка параметров указывается слово
override
7. Виртуальные методы
Виртуальныеметоды
используются
для
поддержки
динамического полиморфизма. Его основой являются указатели на
производные классы.
Указатель на базовый класс может использоваться, как
указатель на любой класс, производный от этого базового, поэтому
верно:
base *p; // указатель базового класса
base base_ob; // объект базового класса
derived derived_ob; // объект производного
р = &base_ob; // настроили на базовый класс
р = &derived_ob; // настроили на производный
8. Доступ к объектам через указатели
Через указатель базового класса доступ можетбыть обеспечен только к объектам производного
класса, унаследованным от базового. Указатель
производного класса нельзя использовать для
доступа к объектам базового класса.
Если указатель базового класса указывает на
объект
производного
класса,
а
затем
инкрементируется, то он будет указывать на
следующий объект базового класса
9. Вызов виртуального метода
Если указатель базового класса ссылается на объектпроизводного,
содержащего
виртуальный
метод
и
осуществляет вызов через указатель, то компилятор вызывает
версию метода, основываясь на типе объекта.
Этот процесс происходит во время выполнения программы и
является
реализацией
принципа
динамического
полиморфизма.
Деструкторы могут быть виртуальными, а конструкторы нет.
Виртуальные методы имеют иерархический порядок
наследования.
Если виртуальный метод не переопределяется в производном
классе, то используется версия, определенная в базовом
классе.
10. Вызов виртуального метода
#include <iostream>using namespace std;
class B {
public :
int i;
B (int x) { i = x; }
virtual void f() override
{cout << "Выполнение f() класса B";
cout << i <<endl; }
};
class D1 : public B {
public :
D1(int x) : B(x) { }
void f () override
{cout <<"Выполнение f() в D1"; cout << i * i <<endl ;}
};
11. Продолжение программы
class D2: public B {public:
D2 (int x): B(x) { }
void f () override
{cout << "Выполнение f() класса D2" <<i + i <<"\n" ; }
};
int main()
{B *p;
B ob(15) ;
D1 d_obl(14);
D2 d_ob2(11);
p = &ob;
p->f(); //метод класса base
p = &d_obl;
p->f(); // метод класса D1
p = &d_ob2;
p->f(); // метод класса D2
return 0;
}
12. Чистые виртуальные функции
Если виртуальная функция объявленная в базовом классе невыполняет никаких действий, тогда в любом классе,
производном от этого базового она обязательно должна быть
переопределена. Для реализации этого положения в C++
поддерживаются так называемые чистые виртуальные
функции.
Определение:
virtual тип имя_функции(список_параметров)=0;
Если класс содержит хотя бы одну чистую виртуальную
функцию, то о нем говорят как об абстрактном классе.
Поскольку в абстрактном классе содержится, по крайней мере,
одна функция, у которой отсутствует тело функции, технически
такой класс неполон, и ни одного объекта этого класса создать
нельзя. Таким образом, абстрактные классы могут быть только
наследуемыми.
13. Пример чистые виртуальные методы
#include <iostream>using namespace std;
class area {
double dim1, dim2; // размеры фигуры
public:
void setarea(double d1, double d2)
{dim1 = d1; dim2 = d2;}
void getdim(double &d1, double &d2)
{d1 = dim1;d2 = dim2;}
virtual double getarea() = 0;
};
class rectangle: public area {
public:
double getarea(){
double d1, d2;
getdim(d1, d2);
return d1 * d2;
}
};
14. Пример с абстрактным классом
class triangle: public area {public:
double getarea()
{double d1, d2;
getdim (d1, d2);
return 0.5 * d1 * d2;}
};
int main()
{area *p;
rectangle r;
triangle t;
r.setarea (3.3, 4.5);
t.setarea (4.0, 5.0);
p = &r;
cout<<"Площадь прямоугольника:"<<p->getarea();
p = &t;
cout<< "\nПлощадь треугольника:"<< p->getarea();
return 0;
}
15. Запрет переопределения методов
С помощью спецификатора final можно запретить переопределениеметодов в производных классах.
class Person
{
public:
virtual void print() const final
{
};
}
class Employee : public Person
{
public:
void print() const override // Ошибка!!!
{
}
};
16. Виртуальная функция при наследовании остается виртуальной
#include <iostream>using namespace std;
class B {
protected:
int i;
public:
B (int j=0){i=j;}
virtual void f(){cout << i*i<<endl;}
};
class D1: public B {
public:
D1(int j):B(j){}
void f(){cout<<i*i*i<<endl;}
};
17. Окончание программы
class D2: public D1 {public:
D2(int j): D1 (j){}
void f(){cout<<2*i<<endl;}
};
int main(){
B *p, ob;
D1 d_ob1(30);D2 d_ob2(60);
p = &ob;
p->f(); // функция func() базового класса
p = &d_ob1;
p->f(); // функция func()класса derivedl
p = &d_ob2;
p->f(); // функция func()класса derived2
return 0;
}
programming