Рейтинговые книги
Читем онлайн Освой самостоятельно С++ за 21 день. - Джесс Либерти

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 88 89 90 91 92 93 94 95 96 ... 170

37:    return 0;

38: }

39:

40: void TelepathicFunction()

41: {

42:    cout << "There are " << Cat::GetHowMany() << " cats alive!n";

43: }

Результат:

There are 1 cats alive!

There are 2 cats alive!

There are 3 cats alive!

There are 4 cats alive!

There are 5 cats alive!

There are 4 cats alive!

There are 3 cats alive!

There are 2 cats alive!

There are 1 cats alive!

There are 0 cats alive!

Анализ: В строке 15 в объявлении класса Cat создается закрытая статическая переменная-член HowManyCats. В строке 12 объявляется открытая статическая функция-член GetHowMany().

Так как функция GetHowMany() открыта, доступ к ней может получить любая другая функция, а при объявлении ее статической отпадает необходимость в существовании объекта типа Cat. Именно поэтому функция TelepathicFunction() в строке 42 может получить доступ к GetHowMany(), не имея доступа к объекту Cat. Конечно же, к функции GetHowMany() можно было обратиться из блока main() так же, как к обычным методам объектов Cat.

Примечание: Статические функции-члены не содержат указателя this. Поэтому они не могут объявляться со спецификатором const. Кроме того, поскольку функции-члены получают доступ к переменным-членам с помощью указателя this, статические функции-члены не могут использовать обычные нестатические переменные-члены!

Статические функции-члены

Доступ к статическим функциям-членам можно получить, либо вызывая их из объектов класса как обычные функции-члены, либо вызывая их без объектов, явно указав в этом случае имя класса. Пример:

class Cat

{

   public:

      static int GetHowMany() { return HowManyCats; }

   private:

      static int HowManyCats;

}

int Cat::HowManyCats = 0;

int main()

{

   int howMany;

   Cat theCat; // определение обьекта

   howMany = theCat.GetHowMany(); // доступ через объект

   howMany = Cat::GetHowMany(); // доступ без объекта

}

Указатели на функции

Точно так же, как имя массива постоянно указывает на его первый элемент, имя функции является указателем на саму функцию. Можно объявить переменную-указатель функции и в дальнейшем вызывать ее с помощью этого указателя. Такая возможность может оказаться весьма полезной, поскольку позволяет создавать программы, в которых функции вызываются по командам пользователя, вводимым с клавиатуры.

Единственная важная деталь для определения указателя на функцию — знание типа объекта, на который ссылается указатель. Указатель типа int обязательно связан с целочисленной переменной. Аналогичным образом указатель на функцию может вызывать только функции с заданными сигнатурой и типом возврата.

В объявлении

long (*funoPtr) (int);

создается указатель на функцию funcPtr (обратите внимание на символ * перед именем указателя), которая принимает целочисленный параметр и возвращает значение типа long. Круглые скобки вокруг (*funcPtr) обязательны, поскольку скобки вокруг (int) имеют больший приоритет по сравнению с оператором косвенного обращения (*). Если убрать первые скобки, то это выражение будет объявлять функцию funcPtr, принимающую целочисленный параметр и возвращающую указатель на значение типа long. (Вспомните, что все пробелы в C++ игнорируются,) Рассмотрим два следующих объявления:

long * Function (int); long (*funcPtr) (int);

В первой строке Function() — это функция, принимающая целочисленный параметр и возвращающая указатель на переменную типа long. Во втором примере funcPtr — это указатель на функцию, принимающую целочисленный параметр и возвращающую переменную типа long.

Объявление указателя на функцию всегда содержит тип возвращаемой переменной и заключенный в скобки список типов формальных параметров, если таковые имеются. Пример объявления и использования указателя на функцию показан в листинге 14.5.

Листинг 14.5. Указатели на функцию

1: // Листинг 14.5. Использование указателей на функции

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: void PrintVals(int, int);

10:

11: int main()

12: {

13:    void (* pFunc) (int &, int &);

14:    bool fQuit = false;

15:

16:    int val0ne=1, valTwo=2;

17:    int choice;

18:    while (fQuit == false)

19:    {

20:       cout << "(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap";

21:       cin >> choice;

22:       switch (choice)

23:       {

24:          case 1: pFunc = GetVals; break;

25:          case 2: pFunc = Square; break;

26:          case 3: pFunc = Cube; break;

27:          case 4: pFunc = Swap; break;

28:          default : fQuit = true; break;

29:       }

30:

31:       if (fQuit)

32:          break;

33:

34:       PrintVals(valOne, valTwo);

35:       pFunc(valOne, valTwo);

36:       PrintVals(valOne, valTwo);

37:    }

38:    return 0;

39: }

40:

41: void PrintVals(int x, int y)

42: {

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)0uit (1)Change Values (2)Square (3)Cube (4)Swap: 1

x: 1 у: 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)Qult (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

Анализ: В строках 5—8 объявляются четыре функции с одинаковыми типами возврата и сигнатурами. Все эти функции возвращают void и принимают ссылки на значения типа int.

В строке 13 переменная pFunc объявлена как указатель на функцию, принимающую две ссылки на int и возвращающую void. Этот указатель может ссылаться на каждую из упоминавшихся ранее функций. Пользователю предлагается выбрать функцию, после чего она связывается с указателем pFunc. В строках 34—36 выводятся текущие значения двух целочисленных переменных, вызывается текущая функция и выводятся результаты вычислений.

Указатели на функции

Обращение к функции через указатель записывается так же, как и обычный вызов функции, на которую он указывает. Просто вместо имени функции используется имя указателя на эту функцию.

Чтобы связать указатель на функцию с определенной функцией, нужно просто присвоить ему имя функции без каких-либо скобок. Имя функции. как вы уже знаете, представляет собой константный указатель на саму функцию. Поэтому указатель на функцию используется так же, как и ее имя. При вызове функции через указатель следует задать все параметры. установленные для текущей функции. Пример:

long(*pFuncOne) (int,int);

long SomeFunction (int,int);

pFuncOne = SomeFunction;

pFuncOne (5,7);

Зачем нужны указатели на функции

В программе, показанной в листинге 14.5, можно было бы обойтись и без указателей на функции, однако с их помощью значительно упрощается и становится читабельнее код программы: достаточно только выбрать функцию из списка и затем вызвать ее.

В листинге 14.6 используются прототипы и объявления функций листинга 14.5, но отсутствуют указатели на функции. Оцените различия между этими двумя листингами.

Листинг 14.6. Видоизмененный вариант листинга 14.5 без использования указателей на функции

1: // Листинг 14.6. Видоизмененный вариант листинга 14.5 без использования

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: void PrintVals(int, int);

10:

11: int main()

12: {

13:    bool fQuit = false;

14:    int valOne=1, valTwo=2;

15:    int choice;

16:    while (fQuit == false)

17:    {   

18:       cout << << "(0)Quit (1)Change Values (2)Square (3)Cube (4)Swap";

19:       cin >> choice;

20:       switch (choice)

21:       {

22:          case 1:

23:             PrintVals(valOne, valTwo);

24:             GetVals(valOne, valTwo);

25:             PrintVals(valOne, valTwo);

26:             break;

27:

28:          case 2:

29:             PrintVals(valOne, valTwo);

20:             Square(valOne,valTwo);

31:             PrintVals(valOne, valTwo);

32:             break;

33:

34:          case 3:

35:             PrintVals(valOne, valTwo);

36:             Cube(valOne, valTwo);

37:             PrintVals(valOne, valTwo);

1 ... 88 89 90 91 92 93 94 95 96 ... 170
На этой странице вы можете бесплатно читать книгу Освой самостоятельно С++ за 21 день. - Джесс Либерти бесплатно.

Оставить комментарий