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

int calc( int, int );

int (*pfi2s)( const string , const string ) = 0;

int (*pfi2i)( int, int ) = 0;

int main() {

pfi2i = calc; // правильно

pri2s = calc; // ошибка: несовпадение типов

pfi2s = pfi2i; // ошибка: несовпадение типов

return 0;

}

Такой указатель можно инициализировать нулем или присвоить ему нулевое значение, в этом случае он не адресует функцию.

<p>7.9.3. Вызов</p>

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

#include

int min( int*, int );

int (*pf)( int*, int ) = min;

const int iaSize = 5;

int ia[ iaSize ] = { 7, 4, 9, 2, 5 };

int main() {

cout ia[ ix ] )

minVal = ia[ ix ];

return minVal;

}

Вызов

pf( ia, iaSize );

может быть записан также и с использованием явного синтаксиса указателя:

(*pf)( ia, iaSize );

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

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

<p>7.9.4. Массивы указателей на функции</p>

Можно объявить массив указателей на функции. Например:

int (*testCases[10])();

testCases – это массив из десяти элементов, каждый из которых является указателем на функцию, возвращающую значение типа int и не имеющую параметров.

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

В этом случае помогает использование имен, определенных с помощью директивы typedef:

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

typedef int (*PFV)(); // typedef для указателя на функцию

PFV testCases[10];

Данное объявление эквивалентно предыдущему.

Вызов функций, адресуемых элементами массива testCases, выглядит следующим образом:

const int size = 10;

PFV testCases[size];

int testResults[size];

void runtests() {

for ( int i = 0; i

Массив указателей на функции может быть инициализирован списком, каждый элемент

которого является функцией. Например:

int lexicoCompare( const string , const string );

int sizeCompare( const string , const string );

typedef int ( *PFI2S )( const string , const string );

PFI2S compareFuncs[2] =

{

lexicoCompare,

sizeCompare

};

Можно объявить и указатель на compareFuncs, его типом будет “указатель на массив указателей на функции”:

PFI2S (*pfCompare)[2] = compareFuncs;

Это объявление раскладывается на составные части следующим образом:

(*pfCompare)

Оператор разыменования говорит, что pfCompare является указателем. [2] сообщает о количестве элементов массива:

(*pfCompare) [2]

PFI2S – имя, определенное с помощью директивы typedef, называет тип элементов. Это “указатель на функцию, возвращающую int и имеющую два параметра типа const string ”. Тип элемента массива тот же, что и выражения lexicoCompare.

Такой тип имеет и первый элемент массива compareFuncs, который может быть получен с помощью любого из выражений:

compareFunc[ 0 ];

(*pfCompare)[ 0 ];

Чтобы вызвать функцию lexicoCompare через pfCompare, нужно написать одну из следующих инструкций:

// эквивалентные вызовы

pfCompare [ 0 ]( string1, string2 ); // сокращенная форма

Перейти на страницу:

Похожие книги