Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Язык программирования C++. Пятое издание - Стенли Липпман

Язык программирования C++. Пятое издание - Стенли Липпман

Читать онлайн Язык программирования C++. Пятое издание - Стенли Липпман

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 81 82 83 84 85 86 87 88 89 ... 297
Перейти на страницу:

// объявление функции pf(), возвращающей указатель на тип bool

bool *pf(const string &, const string &);

Использование указателей на функцию

При использовании имени функции как значения функция автоматически преобразуется в указатель. Например, адрес функции lengthCompare() можно присвоить указателю pf следующим образом:

pf = lengthCompare;  // pf теперь указывает на функцию lengthCompare

pf = &lengthCompare; // эквивалентное присвоение: оператор обращения к

                     // адресу необязателен

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

bool b1 = pf("hello", "goodbye");            // вызов lengthCompare

bool b2 = (*pf)("hello", "goodbye");         // эквивалентный вызов

bool b3 = lengthCompare("hello", "goodbye"); // эквивалентный вызов

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

string::size_type sumLength(const string&, const string&);

bool cstringCompare(const char*, const char*);

pf = 0;              // ok: pf не указывает на функцию

pf = sumLength;      // ошибка: разные типы возвращаемого значения

pf = cstringCompare; // ошибка: разные типы параметров

pf = lengthCompare;  // ok: типы функции и указателя совпадают точно

Указатели на перегруженные функции

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

void ff(int*);

void ff(unsigned int);

void (*pf1)(unsigned int) = ff; // pf1 указывает на ff(unsigned)

Компилятор использует тип указателя для выявления используемой версии перегруженной функции. Тип указателя должен точно соответствовать одной из версий перегруженной функции:

void (*pf2)(int) = ff;     // ошибка: нет версии с точно таким списком

                           // параметров

double (*pf3) (int*) = ff; // ошибка: тип возвращаемого значения

                           // функций ff и pf3 не совпадают

Указатель на функцию как параметр

Подобно массивам (см. раздел 6.2.4), нельзя определить параметры типа функции, но можно создать параметр, являющийся указателем на функцию. Как и в случае с массивами, можно создать параметр, который выглядит как тип функции, но обрабатывается как указатель:

// третий параметр имеет тип функции и автоматически обрабатывается как

// указатель на функцию

void useBigger(const string &s1, const string &s2,

               bool pf(const string&, const string&));

// эквивалентное объявление: параметр явно определен как указатель

// на функцию

void useBigger(const string &s1, const string &s2,

               bool (*pf)(const string&, const string&));

При передаче функции как аргумента это можно сделать непосредственно. Аргумент будет автоматически преобразован в указатель:

// автоматическое преобразование функции lengthCompare в указатель

// на нее

useBigger(s1, s2, lengthCompare);

Как можно заметить в объявлении функции useBigger(), написание указателей на тип функций быстро становится утомительным. Псевдонимы типа (см. раздел 2.5.1), а также спецификатор decltype (см. раздел 2.5.3) позволяют упростить код, который использует указатели на функции:

// Func и Func2 имеют тип функции

typedef bool Func(const string&, const strings);

typedef decltype(lengthCompare) Func2; // эквивалентный тип

// FuncP и FuncP2 имеют тип указателя на функцию

typedef bool(*FuncP)(const string&, const string&);

typedef decltype(lengthCompare) *FuncP2; // эквивалентный тип

Здесь при определении типов использовано ключевое слово typedef. И Func, и Func2 являются типами функций, тогда как FuncP и FuncP2 — типы указателя. Следует заметить, что спецификатор decltype возвращает тип функции; автоматического преобразования в указатель не происходит. Поскольку спецификатор decltype возвращает тип функции, при необходимости получить указатель следует добавить символ *. Можно повторно объявить функцию useBigger(), используя любой из этих типов:

// эквивалентные объявления useBigger с использованием псевдонимов типа

void useBigger(const string&, const string&, Func);

void useBigger(const string&, const string&, FuncP2);

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

Возвращение указателя на функцию

Подобно массивам (см. раздел 6.3.3), нельзя возвратить тип функции, но можно возвратить указатель на тип функции. Точно так же тип возвращаемого значения следует писать как тип указателя; компилятор не будет автоматически рассматривать тип возвращаемого значения функции как соответствующий тип указателя. Как и при возвращении массива, безусловно, проще всего объявить функцию, которая возвращает указатель на функцию, при помощи псевдонима типа:

using F = int(int*, int);     // F - тип функции, а не указатель

using PF = int(*)(int*, int); // PF - тип указателя

Здесь для определения F как типа функции и PF как указателя на тип функции было использовано объявление псевдонима типа (см. раздел 2.5.1). Имейте в виду, что в отличие от параметров, имеющих тип функции, тип возвращаемого значения не преобразуется автоматически в тип указателя. Следует явно определить, что тип возвращаемого значения является типом указателя:

PF f1(int); // ok: PF - указатель на функцию; f1 возвращает указатель

            // на функцию

F f1(int);  // ошибка: F - тип функции; f1 не может возвратить функцию

F *f1(int); // ok: явное определение типа возвращаемого значения как

            // указателя на функцию

Конечно, функцию f1() также можно объявить непосредственно:

int (*f1(int))(int*, int);

Читая это объявление изнутри наружу, можно заметить у f1 список параметров, таким образом, f1 — это функция. Имени f1 предшествует знак *, следовательно, функция f1() возвращает указатель. У типа самого указателя тоже есть список параметров, таким образом, указатель указывает на функцию. Эта функция возвращает тип int.

И наконец, следует обратить внимание на то, что объявления функций, которые возвращают указатель на функцию, можно упростить при помощи замыкающего типа возвращаемого значения (см. раздел 6.3.3):

auto f1(int) -> int (*)(int*, int);

Использование спецификаторов auto и decltype для типов указателей на функции

Если известно, какую функцию (функции) следует возвратить, можно использовать спецификатор decltype для упрощения записи типа возвращаемого значения в виде указателя на функцию. Предположим, например, что имеются две функции, обе возвращают тип string::size_type и имеют два параметра типа const string&. Можно написать третью функцию, которая получает параметр типа string и возвращает указатель на одну из следующих двух функций следующим образом:

string::size_type sumLength(const string&, const string&);

string::size_type largerLength(const string&, const string&);

// в зависимости от значения строкового параметра функция getFcn

// возвращает указатель на sumLength или largerLength

decltype(sumLength) *getFcn(const string &);

Единственная сложность в объявлении функции getFcn() — это необходимость помнить, что при применении спецификатора decltype к функции она возвращает тип функции, а не указатель на тип функции. Чтобы получить указатель, а не функцию, следует добавить знак *.

Упражнения раздела 6.7

Упражнение 6.54. Напишите объявление функции, получающей два параметра типа int, и возвращающей тип int. Объявите также вектор, элементами которого является тип указателя на эту функцию.

Упражнение 6.55. Напишите четыре функции, которые добавляют, вычитают, умножают и делят два значения типа int. Сохраните указатели на эти значения в векторе из предыдущего упражнения.

1 ... 81 82 83 84 85 86 87 88 89 ... 297
Перейти на страницу:
На этой странице вы можете бесплатно скачать Язык программирования C++. Пятое издание - Стенли Липпман торрент бесплатно.
Комментарии