1) прототипы виртуальной функции в базовом классе и во всех производных классах должны соответствовать друг другу (тип возвращаемого значения, имя функции, число и тип принимаемых параметров должны совпадать). В противном случае функция рассматривается как перегруженная, а не виртуальная;
2) виртуальная функция должна быть компонентом класса;
3) конструктор не может быть виртуальной функцией, хотя деструктор можно объявить со спецификатором virtual.
Если функция не описана (пропущена) в производном классе, то используется версия базового класса.
Использование виртуальных функций.
Обычно при проектировании программы общие атрибуты иерархических классов представляются в определении базовых классов, частные - в особых производных классах.
Функции, которые можно определить без знания особенностей конкретного объекта, используемого в программе, объявляются как обычные методы классов или функции программ.
Функции, определения которых зависят от конкретных параметров объектов, удобно объявить виртуальными.
Отметим, что механизм виртуальных функций и множественного наследования дает естественную возможность расширения библиотечных приложений путем наследования всего, что присуще базовым классам, с одновременной возможностью включения дополнительных средств, чтобы заставить новые объекты работать надлежащим образом.
Рассмотрим демонстрационный пример использования виртуальных функций:
struct B {
virtual void vf1();
virtual void vf2();
virtual void vf3();
void f();}
class D: public B {
virtual void vf1();
//виртуальная ф-я, спецификатор virtual допустим, но избыточен
void vf2(int);
//другой список аргументов, функция не является виртуальной
char vf3();//ошибка, т.к. изменяется только тип возвращаемого значения,
//что недопустимо
void f();}; //обычный метод класса D
void main (void) { B b, *bp; //объект и указатель класса B
bp=&b; //присвоение указателю адреса объекта
bp->vf1(); //вызывается B::f1();
D d; //объявлен объект d класса D
bp=&d; //присвоение указателю на базовый класс B адреса объекта
//производного класса d;
bp->vf1(); //вызывается D::vf1();
bp->vf2(); //вызывается B::vf2();, т.к. функция
//vf2(int) из D имеет другой список аргументов и не является
//виртуальной функцией;
bp->f(); } //вызов B::f() - не виртуального метода из класса B, так как
//невиртуальные методы класса D для указателя из класса B неизвестны.
Указатель "видит" только имена методов, которые объявлены в его собственном классе (классе, в котором объявлен указатель). Переопределенная функция vf1() в классе D автоматически становится виртуальной. Используемый для vf1() спецификатор virtual, вообще говоря, является избыточным.
Интерпретация вызова виртуальной функции зависит от типа объекта, для которого она вызывается. Связывание осуществляется в момент реального вызова метода. В случае вызова невиртуальной функции интерпретация зависит только от типа указателя или ссылки, с помощью которого они вызываются. Вызывается объект из класса, в котором объявлен указатель.
Функция, объявленная виртуальной, сохраняет это свойство (свойство виртуальности) для любого производного класса, на любом уровне вложенности. Если в некотором производном классе виртуальная функция не переопределена, то используется ее версия из базового класса.
АБСТРАКТНЫЕ КЛАССЫ
Для ситуаций, в которых при пропуске переопределения виртуальной функции в производном классе нельзя использовать ее версию из базового класса, можно объявить так называемую чистую (pure) виртуальную функцию (функцию без постороннего эффекта).
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.