
- •Введение в понятие класса
- •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)
Виртуальные функции
Полиморфизм во время выполнения программы поддерживается использованием производных типов и виртуальных функций. Виртуальные функции – это функции, которые объявляются с использованием ключевого слова virtual в базовом классе и переопределяются (override) в одном или нескольких производных классах. При этом прототипы функций в разных классах одинаковы. Для виртуальной функции имеет место следующее; при вызове функции, объявленной виртуальной через указатель на базовый тип, во время выполнения программы определяется, какая виртуальная функция будет вызвана, в зависимости от того, на какой объект какого класса будет настроен указатель. Получаем, что когда указателю базового типа присвоены адреса объектов различных производных классов, выполняются различные версии виртуальных функций.
Виртуальная функция объявляется виртуальной в базовом классе с помощью ключевого слова virtual. При переопределении функции в производном классе это слово не указывается.
Рассмотрим пример:
class Base {
public:
virtual void show(void)
{ cout << “В базовом класее Base\n;}
};
class Derive:public Base{
void show(void)
{ cout<<”В производном классе Derive\n”;}
};
class Derive1:public Derive{
void show(void)
{ cout<<”В производном классе Derive1\n”;}
};
class Derive2:public Derive1{
void show(void)
{ cout<<”В производном классе Derive2\n”;}
};
void main(void)
{
Base bobj, *pb;
Derive dobj, *pd;
Derive1 d1obj, *pd1;
Derive2 d2obj, *pd2;
pb=&bobj;
pb->show(); // вызов функции show() класса Base
pd=&dobj; // вызов функции
pd->show(); // show() класса Derive виртуальность функции не исп.
pd1=&d1obj; // вызов функции
pd1->show(); // show() класса Derive1
pd2=&d2obj; // вызов функции
pd2->show(); // show() класса Derive2
pb=&dobj; // указателю на базовый класс присвоен
// адрес производного класса Derive
pb->show(); // вызов show() класса Derive, исп. Механизм вирт. Функций
pb=&d1obj; // указателю на базовый класс присвоен
// адрес производного класса Derive1
pb->show(); // вызов show() класса Derive1
pd1=&d2obj; // указателю на базовый класс Derive1 присвоен
// адрес производного класса Derive2
pd1->show(); // вызов функции show() класса Derive2
// работает механизм виртуальных функций
pd1->Base::show(); // Явный вызов функции show() класса Base!
pd1->Derive::show(); // Явный вызов функции show() класса Derive!
((Derive2 *)pb)->show(); // Вызов функции show() класса Derive2
}
Замечания к использованию виртуальных функций
Виртуальная функция должна быть членом класса. Она не может быть дружественной для класса, в котором определена, но - дружественной к другому классу. Функция, которая объявлена виртуальной, остается виртуальной не зависимо от того, сколько производных классов построено. Если в рассмотренном примере класс Derive1 будет производным классом для Derive, а не для Base, то функция show() в классе Derive1 остается виртуальной. Если в производном классе функция не замещает виртуальную, так как она не объявлена или имеет другой прототип, то вызывается функция базового класса.
Виртуальные функции удобны для использования, так как в общем случае, базовый класс задает основной интерфейс, который будут иметь производные классы, а производные классы задают свой метод. Для описания полиморфизма часто используется понятие “один интерфейс, много методов”. Так как ООП позволяет создавать сложные программы, то при корректном построении производных классов все объекты, начиная с базового класса, доступны с помощью одного и того же метода, то нужно помнить только интерфейс. Отделение интерфейса от наполнения функций позволяют создавать классы библиотек (class libraries).
Вызов виртуальной функции реализуется как непрямой вызов по таблице виртуальных функций класса. Таблицу создает компилятор, а связывание происходит во время выполнения. Термин позднее связывание (late binding)