Функция Input ( ) объявлена невиртуальной в базовом классе Coord и переопределена в производных классах Dot и Vec.
Void main ( )
{
Coord* pC = new Coord ( ) ; // объявляет указатель на координаты и выделяет память
Dot* pD = new Dot ( 'D' ) ; // объявляет указатель на точку и выделяет память
Vec* pV = new Vec ("V" ) ; // объявляет указатель на вектор и выделяет память
pC->Input ( ) ; // вызывает невиртуальную функцию Coord :: Input ( )
pC->Print ( ) ; // вызывает виртуальную функцию Coord :: Print ( )
pC = pD ; // указатель на координаты получает адрес объекта типа точки
pC->Input ( ) ; // вызывает невиртуальную функцию Coord :: Input ( )
pC->Print ( ) ; // вызывает виртуальную функцию Dot :: Print ( )
pC = pV ; // указатель на координаты получает адрес объекта типа вектора
pC->Input ( ) ; // вызывает невиртуальную функцию Coord :: Input ( )
pC->Print ( ) ; // вызывает виртуальную функцию Vec :: Print ( )
}
В приведённом примере указатель на координаты pC поочерёдно принимает значения адреса объектов координат, точки и вектора. Несмотря на то, что тип указателя pC не изменяется, он вызывает различные виртуальные функции в зависимости от своего значения.
При использовании указателя на базовый класс, который реально указывает на объект производного класса, вызывается невиртуальная функция базового класса.
Необходимо отметить, что операция присвоения pC = pD, в которая использует операнды различных типов (Coord* и Dot*) без преобразования, возможна только для указателя на базовый класс в левой части. Обратная операция присвоения pD = pC недопустима и вызывает ошибку синтаксиса.
При выполнении программа выводит на экран:
x = 1
y = 1
x = 1 y = 1
x = 2
y = 2
Координаты точки D : x = 2 y = 2
x = 3
y = 3
Проекции вектора V : x = 3 y = 3
При вызове функции с помощью указателей и ссылок, применяются следующее правила:
1. .. вызов виртуальной функции разрешается в соответствии с типом объекта, адрес которого хранит указатель или ссылка;
2. .. вызов невиртуальной функции разрешается в соответствии с типом указателя или ссылки.
Виртуальные функции вызываются только для объектов, принадлежащих некоторому классу. Поэтому нельзя объявить глобальную или статическую функцию виртуальной. Ключевое слово virtual может быть использовано при объявлении переопределяемой функции в производном классе, однако оно не является обязательным: переопределённые виртуальные функции сами являются виртуальными функциями.
Виртуальные функции, объявленные в базовом классе, должны быть в нем определены, если они не объявлены как чисто виртуальные. Функция, объявленная в производном классе, переопределяет виртуальную функцию в базовом классе только тогда, когда имеет то же имя и работает с тем же количеством и типами параметров, что и виртуальная функция базового класса. Если они отличаются типом хоть одного параметра, то функция в производном классе считается совершенно новой и переопределения не происходит. Функция в производном классе не может отличаться от виртуальной функции в базовом классе только своим возвращаемым значением, должен также отличаться список аргументов.
Использование указателей на объекты, содержащие виртуальные функции, позволяет изменять поведение объекта в ходе выполнения программы за счёт изменения его значения. Это эквивалентно изменению типа идентификатора уже после его объявления.
Виртуальные деструкторы
Конструкторы не могут быть виртуальными, однако деструкторы могут быть виртуальными, и часто ими являются. Рассмотрим базовый класс с виртуальным деструктором. Объявляем указатель на объект базового класса и передаём ему адрес объекта производного класса. Такая операция допустима и часто используется.
При удалении объекта производного класса будет вызван деструктор производного класса. Затем деструктор производного класса вызовет деструктор базового класса, и объект будет правильно удален (удален целиком).
Если деструктор базового класс не является виртуальным, то будет вызван только деструктор базового класса и произойдет утечка памяти. Рассмотрим пример:
Дата добавления: 2016-10-17; просмотров: 487;