Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

// typedef представляет собой тип функции

typedef int functype( const string &, const string & );

void sort( string *, string *, functype );

void sort( string *, string *,

sort() рассматривается компилятором как объявленная в виде int (*)( const string &, const string & ) );

Два этих объявления sort() эквивалентны.

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

int (*ff( int ))( int*, int );

ff() объявляется как функция, имеющая один параметр типа int и возвращающая указатель на функцию типа

int (*)( int*, int );

И здесь использование директивы typedef делает объявление понятнее. Объявив PF с

//Использование директивы typedef делает

//объявления более понятными

typedef int (*PF)( int*, int );

помощью typedef, мы видим, что ff() возвращает указатель на функцию:

PF ff( int );

Типом возвращаемого значения функции не может быть тип функции. В этом случае

// typedef представляет собой тип функции

typedef int func( int*, int );

выдается ошибка компиляции. Например, нельзя объявить ff() таким образом: func ff( int ); // ошибка: тип возврата ff() - функция

7.9.6. Указатели на функции, объявленные как extern "C"

Можно объявлять указатели на функции, написанные на других языках программирования. Это делается с помощью директивы связывания. Например, указатель pf ссылается на С-функцию:

extern "C" void (*pf)(int);

extern "C" void exit(int);

// pf ссылается на C-функцию exit() extern "C" void (*pf)(int) = exit; int main() {

//...

//вызов С-функции, а именно exit()

(*pf)(99);

Через pf вызывается функция, написанная на языке С.

}

Вспомним, что присваивание и инициализация указателя на функцию возможны лишь тогда, когда тип в левой части оператора присваивания в точности соответствует типу в правой его части. Следовательно, указатель на С-функцию не может адресовать функцию С++ (и инициализация его таким адресом не допускается), и наоборот. Подобная

void (*pfl)(int);

extern "C" void (*pf2)(int); int main() {

pfl = pf2; // ошибка: pfl и pf2 имеют разные типы

// ...

попытка вызывает ошибку компиляции:

}

Отметим, что в некоторых реализациях С++ характеристики указателей на функции С и С++ одинаковы. Отдельные компиляторы могут допустить подобное присваивание, рассматривая это как расширение языка.

Если директива связывания применяется к объявлению, она затрагивает все функции, участвующие в данном объявлении.

В следующем примере параметр pfParm также служит указателем на С-функцию. Директива связывания применяется к объявлению функции, к которой этот параметр

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

относится:

extern "C" void f1( void(*pfParm)(int) );

Следовательно, f1() является С-функцией с одним параметром – указателем на С- функцию. Значит, передаваемый ей аргумент должен быть либо такой же функцией, либо указателем на нее, поскольку считается, что указатели на функции, написанные на разных языках, имеют разные типы. (Снова заметим, что в тех реализациях С++, где указатели на функции С и С++ имеют одинаковые характеристики, компилятор может поддерживать расширение языка, позволяющее не различать эти два типа указателей.)

Коль скоро директива связывания относится ко всем функциям в объявлении, то как же объявить функцию С++, имеющую в качестве параметра указатель на С-функцию? С

//FC представляет собой тип:

//С-функция с параметром типа int, не возвращающая никакого значения

extern "C" typedef void FC( int );

//f2() - C++ функция с параметром -

//указателем на С-функцию

помощью директивы typedef. Например: void f2( FC *pfParm );

Упражнение 7.21

В разделе 7.5 приводится определение функции factorial(). Напишите объявление указателя на нее. Вызовите функцию через этот указатель для вычисления факториала 11.

Упражнение 7.22

(a)int (*mpf) (vector<int>&);

(b)void (*apf[20])(doub1e);

Каковы типы следующих объявлений:

(c) void (*(*papf)[2])(int);

Как сделать эти объявления более понятными, используя директивы typedef? Упражнение 7.23

double

abs(dou

ble);

double

sin(dou

ble);

double

cos(dou

ble);

Вот функции из библиотеки С, определенные в заголовочном файле <cmath>: double sqrt(double);

Как бы вы объявили массив указателей на С-функции и инициализировали его этими четырьмя функциями? Напишите main(), которая вызывает sqrt() с аргументом 97.9 через элемент массива.

Упражнение 7.24

Вернемся к примеру sort(). Напишите определение функции

int sizeCompare( const string &, const string & );

Если передаваемые в качестве параметров строки имеют одинаковую длину, то sizeCompare() возвращает 0; если первая строка короче второй, то отрицательное число, а если длиннее, то положительное. Напоминаем, что длина строки возвращается операцией size() класса string. Измените main() для вызова sort(), передав в качестве третьего аргумента указатель на sizeCompare().