Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
86
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

С++ для начинающих

367

 

// 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);

С++ для начинающих

368

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

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

С++ для начинающих

369

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

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

extern "C" typedef void FC( int );

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

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

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(double); double sin(double); double cos(double);

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

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

Упражнение 7.24

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

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

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