Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СМП Лекция 10.pptx
Скачиваний:
0
Добавлен:
07.07.2024
Размер:
194.13 Кб
Скачать

Пример4 Иерархия ресурсоемких классов 24

Работа иерархии классов со своими методами и базовых классов Окончание

void main()

{ dpoint3 p(-5, 0, 2);

dmatpoint a(3,-4,0,2), b(a), c(b), d(p,1);

cout<<“ p: “; p.output(); p.set(4, 3, 1);

cout<<“ p: “; p.output();

cout<<“ a: “; a.output(); cout<<“ b: “; b.output(); cout<<“ c: “; c.output(); cout<<“ d: “; d.output();

a.set(4, 0, 3);

cout<<“ a: “; a.dpoint2::output(); cout<<“ a: “; a.dpoint3::output(); cout<<“ a: “; a.output();

cout<<“ dist=“<< a.dist()<<endl; cout<<“ dist=“<< a.dist0()<<endl; getch();

}

//Результаты :

p:x=-5 y= 0 z= 2

p:x= 4 y= 3 z= 1

a:x= 3 y=-4 z= 0 m= 2

b:x= 3 y=-4 z= 0 m= 2

c:x= 3 y=-4 z= 0 m= 2

d:x=-5 y= 0 z= 2 m= 1

a:x= 4 y= 0

a: x= 4 y= 0 z= 3

a: x= 4 y= 0 z= 3 m= 2 dist= 5

dist= 5

Виртуальные функции

25

 

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

Классы включающие такие функции называются полиморфными.

Виртуальные функции - это функции, объявленные в базовом классе и

переопределенные в производных классах.

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

Рассмотрим как ведут себя при наследовании не виртуальные компонентные функции с одинаковыми именами, типами и сигнатурами параметров.

26

Пример1 Не виртуальные переопределенные функции классов при наследовании

class base

//базовый класс base

{ public: void print()

{cout<<“/n Base ”; }

};

class dir : public base

//dir наследник base

{ public: void print()

{ cout<<“/n Dir ”; }

};

void main()

{

base B, *pb=&B; dir D, *pd=&D; base *p=&D;

pb->print(); // вывод Base” pd->print(); // вывод Dir” p->print(); // вывод Base”

}

Виртуальные функции

27

 

Продолжение

 

В последнем случае вызывается функция print базового класса, хотя указатель p настроен на объект производного класса. Дело в том, что выбор нужной функции выполняется при компиляции программы и определяется типом указателя, а не его значением. Такой режим называется ранним или статическим связыванием.

Большую гибкость обеспечивает позднее (отложенное) или динамическое связывание, которое предоставляется механизмом виртуальных функций.

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

Виртуальные функции

28

Продолжение

 

Виртуальные методы (функции) – это методы, объявленные с ключевым словом virtual в базовом классе и переопределенная в одном или в нескольких производных классах

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

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

Пример2 Виртуальные переопределенные 29 функции классов при наследовании

class base

//базовый класс base

{ public:

virtual void print()

{cout<<“/n Base ”; }

};

class dir : public base

//dir наследник base

{ public:

virtual void print() { cout<<“/n Dir ”; }

};

void main()

{

base B, *pb=&B; dir D, *pd=&D; base *p=&D;

pb->print(); // вывод Base” pd->print(); // вывод Dir” p->print(); // вывод Dir”

}

Виртуальные функции

30

 

Продолжение

 

В этом случае будет напечатано

Base

Dir

Dir

Т.о. интерпретация каждого вызова виртуальной функции через указатель на базовый класс зависит от значения этого указателя, т.е. от типа объекта, для которого выполняется вызов.

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

Виртуальные функции

31

 

Продолжение

 

Виртуальность наследуется. После того как функция определена как виртуальная, ее повторное определение в производном классе (с тем же

самым прототипом) создает в этом классе новую виртуальную функцию, причем спецификатор virtual может не использоваться.

Конструкторы не могут быть виртуальными, в отличие от деструкторов. Практически каждый класс, имеющий виртуальную функцию, должен иметь виртуальный деструктор.

Если в производном классе ввести функцию с тем же именем и типом, но с другой сигнатурой параметров, то эта функция производного класса не будет виртуальной.

Механизм виртуального вызова может быть подавлен с помощью явного использования полного квалифицированного имени.

Пример3 Виртуальные переопределенные 32 функции классов при наследовании

class base

//базовый класс base

{ public:

virtual void print()

{cout<<“/n Base ”; }

};

class dir : public base

//dir наследник base

{ public: void print()

{ cout<<“/n Dir ”; }

};

void main()

{

base B, *pb=&B; dir D, *pd=&D; base *p=&D;

pb->print(); // вывод Base” pd->print(); // вывод Dir” p->print(); // вывод Dir” p-> base::print();

// вывод Base”

}

Пример4 Иерархия классов с

33

виртуальными функциями при

 

наследовании

 

class A

{ protected : int a;

public :

virtual void input ()

{ cout << “ a=“ ; cin >> a; } virtual int show () {return a;} int showall () {return show ();}

};

class B : public A { protected :

int b; public :

[virtual] void input () { A :: input();

cout << “ b=“ ; cin >> b;

}

[virtual] int show () {return b;}

};