Освой самостоятельно С++ за 21 день.
Шрифт:
(0)Quit (1)dog (2)cat (3)horse: 0
Анализ: В строках 4—14 объявляется тип абстрактных данных Mammal с двумя чистыми виртуальными методами Speak и Move. От класса Mammal производятся подклассы Dog, Cat и Horse, в каждом из которых замещаются соответствующим образом функции Speak и Move.
В процессе выполнения тела функции main пользователю предлагается выбрать животное, после чего в области динамического обмена создается новый подкласс выбранного
Затем пользователь выбирает метод, который связывается с указателем pFunc. В строке 70 выбранный метод вызывается для созданного объекта посредством предоставления доступа к объекту с помощью указателя ptr и к функции с помощью указателя pFunc.
Наконец, строкой 71 для указателя ptr вызывается функция delete, которая очищает область памяти, занятую созданным ранее объектом. Заметьте, что нет смысла вызывать delete для pFunc, поскольку последний является указателем на код, а не на объект в области памяти. Хотя даже при попытке сделать это вы получите сообщение об ошибке компиляции.
Массивы указателейна функции-члены
Аналогично указателям на обычные функции, указатели на функции-члены могут храниться в массиве. Для инициализации такого массива можно использовать адреса различных функций-членов. В таком случае, чтобы вызвать для объекта тот или иной метод, достаточно просто указать массив и индекс смещения. Именно такой подход применяется в листинге 14.11.
Листинг 14.11. Массив указателей на функции-члены
1: // Листинг 14.11. Массивы указателей на функции-члены
2:
3: #include <iostream.h>
4:
5: class Dog
6: {
7: public:
8: void Speakconst { cout << "Woof!\n"; }
9: void Move const { cout << "Walking to heel...\n"; }
10: void Eat const { cout << "Gobbling food...\n"; }
11: void Growl const { cout << "Grrrrr\n"; }
12: void Whimper const { cout << "Whining noises...\n"; }
13: void RollOver const { cout << "Rolling over...\n"; }
14: void PlayDead const { cout << "Is this the end of Little Caesar?\n";
15: };
16:
17: typedef void (Dog::*PDF)const;
18: int main
19: {
20: const int MaxFuncs = 7;
21: PDF DogFunctions[MaxFuncs] =
22: { Dog::Speak,
23: Dog::Move,
24: Dog::Eat,
25: Dog::Growl,
26: Dog::Whimper,
27: Dog::RollOver,
28: Dog::PlayDead };
29:
30: Dog* pDog =0;
31: int Method;
32: bool fQuit = false;
33:
34: while (!fQuit)
35: {
36: cout << "(0)Quit (1)Speak (2)Move (3)Eat (4)Growl";
37: cout << " (5)Whimper (6)Roll Over (7)Play Dead: ";
38: cin >> Method;
39: if (Method == 0)
40: {
41: fQuit = true;
42: }
43: else
44: {
45: pDog = new Dog;
46: (pDog->*DogFunctions[Method-1]);
47: delete pDog;
48: }
49: }
50: return 0;
51: }
Результат:
(0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll 0ver (7)Play
Dead: 1
Woof!
(0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll 0ver (7)Play
Dead: 4
Grrr
(0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll 0ver (7)Play
Dead: 7
Is this the end of Little Caesar?
(0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll 0ver (7)Play
Dead: 0
Анализ: В строках 5—15 создается класс Dog, содержащий семь функций-членов, характеризующихся одинаковыми сигнатурой и типом возврата. В строке 17 с помощью typedef объявляется тип PDF константных указателей на функции-члены Dog, которые не принимают и не возвращают никаких значений.
В строках 21-28 объявляется массив DogFunctions, предназначенный для хранения указателей на семь функций-членов.
В строках 36 и 37 пользователю предлагается выбрать метод. Выбор любого элемента, кроме Quit, приводит к созданию объекта класса Dog, после чего из массива вызывается соответствующий метод (строка 46). Ниже представлена еще одна строка, которая может немного смутить ваших знакомых программистов, работающих с C++:
(pDog->*-DogFunctions[Method-1]);
Это выражение, безусловно, немного экзотично, но с его помощью можно создать таблицу функций-членов, что сделает код программы проще и читабельнее.
Рекомендуется:Используйте указатели на функции- члены для вызова методов в объектах класса. Используйте typedef, чтобы упростить объявление указателя на функцию-член.
Не рекомендуется:Не злоупотребляйте созданием указателей на функции-члены, если беэ них можно обойтись.
Резюме
Сегодня вы познакомились с созданием статических переменных-членов класса, которые, в отличие от обычных переменных-членов, принадлежат всему классу, а не отдельному объекту. Если статическая переменная-член объявлена как public, то обратиться к ней можно просто по имени, даже не используя объектов класса, которому принадлежит эта переменная.