Использование typedef с указателями на функции
Конструкция void (*)(int&, int&) весьма громоздка. Для ее упрощения можно воспользоваться ключевым словом typedef, объявив новый тип (назовем его VPF) указателей на функции, возвращающие void и принимающие две ссылки на значения типа int. Листинг 14.9 представляет собой переписанную версию листинга 14.8 с использованием этого подхода.
Листинг 14.8. Использование оператора typedef для объявления типа указателей на функции
1: // Листинг 14.9. Использование typedef для
2: // объявления типа указателей на функции
3: #include <iostream.h>
4:
5: void Square (int&,int&);
6: void Cube (int&, int&);
7: void Swap (int&, int &);
8: void GetVals(int&, int&);
9: typedef void (*VPF) (int&, int&);
10: void PrintVals(VPF,int&, int&);
11:
12: int main()
13: {
14: int val0ne=1, valTwo=2;
15: int choice;
16: bool fQuit = false;
17:
18: VPF pFunc;
19:
20: while (fQuit == false)
21: {
22: cout << "(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: ";
23: cin >> choice;
24: switch (choice)
25: {
26: case 1:pFunc = GetVals; break;
27: case 2:pFunc = Square; break;
28: case 3:pFunc = Cube; break;
29: case 4:pFunc = Swap; break;
30: default:fQuit = true; break;
31: }
32: if (fQuit == true)
33: break;
34: PrintVals ( pFunc, valOne, valTwo);
35: }
36: return 0;
37: }
38:
39: void PrintVals( VPF pFunc,int& x, int& y)
40: {
41: cout << "x: " << x << " y: " << y << endl;
42: pFunc(x,y);
43: cout << "x: " << x << " y: " << y << endl;
44: }
45:
46: void Square (int & rX, int & rY)
47: {
48: rX *= rX;
49: rY *= rY;
50: }
51:
52: void Cube (int & rX, int & rY)
53: {
54: int tmp;
55:
56: tmp = rX;
57: rX *= rX;
58: rX = rX * tmp;
59:
60: tmp = rY;
61: rY *= rY;
62: rY = rY * tmp;
63: }
64:
65: void Swap(int & rX, int & rY)
66: {
67: int temp;
68: temp = rX;
69: rX = rY;
|
|
70: rY = temp;
71: }
72:
73: void GetVals (int & rValOne, int & rValTwo)
74: {
75: cout << "New value for ValOne: ";
76: cin >> rValOne;
77: cout << "New value for ValTwo: ";
78: cin >> rValTwo;
79: }
Результат:
(0)Quit (1 )Change Values (2)Square (3)Cube (4)Swap: 1
x: 1 y: 2
New value for ValOne: 2
New value for ValTwo: 3
x: 2 y: 3
(0)Quit (1 )Change Values (2)Square (3)Cube (4)Swap: 3
x: 2 y: 3
x: 8 y: 27
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 2
x: 8 y: 27
x: 64 y: 729
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 4
x: 64 y: 729
x: 729 y: 64
(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 0
Анализ: В строке 9 с помощью оператора typedef объявляется новый тип VPF как указатели на функции, возвращающие void и принимающие две ссылки на int. В строке 10 объявляется функция PrintVals(), которая принимает три параметра: VPF и две ссылки на integer. В строке 18 указатель Pfunc объявляется как принадлежащий TnnyVPF.
После объявления типа VPF дальнейшее использование указателя pFunc и функции PrintVals() становится проще и понятнее. Информация, выводимая программой на экран, не изменилась.
Указатели на функции члены
До настоящего времени все создаваемые указатели на функции использовались для общих функций, не принадлежащих к какому-нибудь одному классу. Однако разрешается создавать указатели и на функции, являющиеся членами классов (методы).
Для создания такого указателя используется тот же синтаксис, что и для указателя на обычную функцию, но с добавлением имени класса и оператора области видимости (::). Таким образом, объявление указателя pFunc на функции-члены класса Shape, принимающие два целочисленных параметра и возвращающие void, выглядит следующим образом:
|
|
void (Shape::*pFunc) (int,int);
Указатели на функции-члены используются так же, как и рассмотренные ранее указатели простых функции. Единственное отличие состоит в том, что для вызова функции необходимо наличие объекта соответствующего класса, для которого вызываются функции. В листинге 14.10 показано использование указателя на метод класса.
Листинг 14.10. Указатели на функции-члены
1: //Листинг 14.10. Указатели на виртуальные функции-члены
2:
3: #include <iostream.h>
4:
5: class Mammal
6: {
7: public:
8: Mammal():itsAge(1) { }
9: virtual ~Mammal() { }
10: virtual void Speak() const = 0;
11: virtual void Move() const = 0;
12: protected:
13: int itsAge;
14: };
15:
16: class Dog : public Mammal
17: {
18: public:
19: void Speak()const { cout << "Woof!\n"; }
20: void Move() const { cout << "Walking to heel...\n"; }
21: };
22:
23:
24: class Cat : public Mammal
25: {
26: public:
27: void Speak()const { cout << "Meow!\n"; }
28: void Move() const { cout << "slinking...\n"; }
29: };
30:
31:
32: class Horse : public Mammal
33: {
34: public:
35: void Speak()const { cout << "Whinny!\n"; }
36: void Move() const 1 cout << "Galloping...\n"; }
|
|
37: };
38:
39:
40: int main()
41: {
42: void (Mammal::*pFunc)() const =0;
43: Mammal* ptr =0;
44: int Animal;
45: int Method;
46: bool fQuit = false;
47:
48: while (fQuit == false)
49: {
50: cout << "(0)Quit (1)dog (2)cat (3)horse
51: cin >> Animal;
52: switch (Animal)
53: {
54: case 1: ptr = new Dog; break;
55: case 2: ptr = new Cat; break;
56: case 3: ptr = new Horse; break;
57: default: fQuit = true; break;
58: }
59: if (fQuit)
60: break;
61:
62: cout << "(1)Speak (2)Move: ";
63: cin >> Method;
64: switch (Method)
65: {
66: case 1: pFunc = Mammal::Speak; break;
67: default: pFunc = Mammal::Move; break;
68: }
69:
70: (ptr->*pFunc)();
71: delete ptr;
72: }
73: return 0;
74: }
Результат:
(0)Quit (1)dog (2)cat (3)horse: 1
(1)Speak (2)Move: 1
Woof!
(0)Quit (1)dog (2)cat (3)horse: 2
(1)Speak (2)Move: 1
Meow!
(0)Quit (1)dog (2)cat (3)horse: 3
(1)Speak (2)Move: 2
Galloping
(0)Quit (1)dog (2)cat (3)horse: 0
Анализ: В строках 4—14 объявляется тип абстрактных данных Mammal с двумя чистыми виртуальными методами Speak() и Move(). От класса Mammal производятся подклассы Dog, Cat и Horse, в каждом из которых замещаются соответствующим образом функции Speak() и Move().
В процессе выполнения тела функции main() пользователю предлагается выбрать животное, после чего в области динамического обмена создается новый подкласс выбранного животного, адрес которого присваивается в строках 54—56 указателю ptr.
Затем пользователь выбирает метод, который связывается с указателем pFunc. В строке 70 выбранный метод вызывается для созданного объекта посредством предоставления доступа к объекту с помощью указателя ptr и к функции с помощью указателя pFunc.
|
|
Наконец, строкой 71 для указателя ptr вызывается функция delete, которая очищает область памяти, занятую созданным ранее объектом. Заметьте, что нет смысла вызывать delete для pFunc, поскольку последний является указателем на код, а не на объект в области памяти. Хотя даже при попытке сделать это вы получите сообщение об ошибке компиляции.
Дата добавления: 2019-02-12; просмотров: 222; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!