|
Программирование >> Дополнительные возможности наследования
5 6 7 8 class Mammal { public: MammalO :itsAge(1) { } virtual MammalO { } virtual void SpeakO const { cout Mammal speak! \ n ; } protected: int itsAge; } ; class Dog : public Mammal { public: void SpeakOconst { cout Woof!\ n ; } } ; class Cat ; public Mammal { public: void SpeakOconst { cout Meow!\ n ; } } ; class Horse : public Mammal { public: void SpeakOconst { cout << Whinny!\ n ; } } ; class Pig : public Mammal { public: void SpeakOconst { cout Oink!\ n ; } } ; int mainO { Mammal* theArray[5]; Mammal* ptr; int choice, i; for ( i = 0; i<5; i++) cout (1)dog (2)cat (3)horse (4)pig: ; cin >> choice; switch (choice) { case 1: ptr = new Dog; Creak; case 2: ptr = new Cat; 55 56 57 58 59 60 61 62 63 64 65 66 67 break; case 3: ptr = new Horse; break; case 4: ptr = new Pig; break; default: ptr = new Mammal; break; theArray[i] = ptr; for (i=0;i<5;i++) theArray[i]->Speak(); return 0; (1)dog (2)cat (3)horse (4)pig (1)dog (2)cat (3)horse (4)pig (1)dog (2)cat (3)horse (4)pig (1)dog (2)cat (3)horse (4)pi9 (1)dog (2)cat (3)horse (A)pig Woof! Meow! Whinny! Oink! Mammal speak! Чтобы идея использования виртуальных функций была понятнее, в данной профамме этот метод раскрыт наиболее явно и четко. Сначала определяется четыре класса - Dog, Cat, Horse и Pig, которые являются производными от базового класса Mammal. В строке 10 объявляется виртуальная функция SpeakO класса Mammal. В Сфоках 18, 25, 32 и 38 указанная функция замещается во всех соответствующих производных классах. Пользователю предоставляется возможность выбрать объект любого производного класса, и в строках 46-64 создается и добавляется в массив указатель класса Mammal на вновь созданный объект. Вопросы о ответы Если функция-член была объявлена как виртуальная в базовом классе, следует ли повторно указывать виртуальность при объявлении этого метода в производном классе? Нет. Если метод уже был объявлен как виртуальный, то он будет оставаться таким, несмотря на замещение его в производном классе. В то же время для повышения читабельности программы имеет смысл (но не требуется) и в производных классах продолжать указывать на виртуальность данного метода с помощью ключевого слова virtual. Во время компиляции неизвестно, объект какого класса захочет создать пользователь и какой именно вариант метода SpeakO будет использоваться. Указатель ptr связывается со своим объектом только во время выполнения программы. Такое связывание указателя с объектом называется динамическим, в отличие от статического связывания, происходящего во время компиляции программы. Как работают виртуальные функции При создании объекта в производном классе, например в классе Dog, сначала вызывается конструктор базового, а затем - производного класса. Схематично объект класса Dog показан на рис. 11.2. Обратите внимание, что объект производного класса состоит как бы из двух частей, одна из которых создается конструктором базового класса, а другая - конструктором производного класса. Часть класса Mammal Объект класса Dog Рис. 11.2. Созданный объект класса Dog Рис. 11.3. Таблица виртуальных функций класса Mammal Если в каком-то из обьектов создается обычная невиртуальная функция, то всю полноту ответственности за эту функцию берет на себя объект. Большинство компиляторов создают таблицы виртуальных функций, называемые также v-таблицами. Такие таблицы создаются для каждого типа данных, и каждый объект любого класса содержит указатель на таблицу виртуальных функций (vptr, или v-указатель). Хотя детали реализации вьшолнения виртуальных функций меняются в разных компиляторах, сами виртуальные функции будут работать совершенно одинаково, независимо от компилятора. Рис. 11.4. Таблица виртуальных функций класса Dog Итак, в каждом объекте есть указатель vptr, который ссылается на таблицу виртуальных функций, содержащую, в свою очередь, указатели на все виртуальные функции. (Более подробно указатели на функции рассматриваются на занятии 14.) Указа-
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |