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

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

363

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

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

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

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

int (*testCases[10])();

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

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

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

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

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

typedef:

PFV testCases[10];

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

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

const int size = 10; PFV testCases[size]; int testResults[size];

void runtests() {

for ( int i = 0; i < size; ++i ) // вызов через элемент массива

testResults[ i ] = testCases[ i ]();

образом:

}

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

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

364

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

следующих инструкций:

((*pfCompare)[ 0 ])( string1, string2 ); // явная форма

7.9.5. Параметры и тип возврата

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

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

365

int sort( string*, string*,

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

И в этом случае директива typedef помогает сделать объявление sort() более

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

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

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

понятным:

int sort( string*, string*, PFI2S );

Поскольку в большинстве случаев употребляется функция lexicoCompare, можно

// значение по умолчанию для третьего параметра

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

использовать значение параметра по умолчанию:

int sort( string*, string*, PFI2S = lexicoCompare );

1 void sort( string *sl, string *s2,

2PFI2S compare = lexicoCompare )

3{

4// условие окончания рекурсии

5if ( si < s2 ) {

6string elem = *s1;

7string *1ow = s1;

8string *high = s2 + 1;

9

10for (;;) {

11while ( compare ( *++1ow, elem ) < 0 && low < s2) ;

12while ( compare( elem, *--high ) < 0 && high > s1)

14if ( low < high )

151ow->swap(*high);

16else break;

17} // end, for(;;)

18

19s1->swap(*high);

20sort( s1, high - 1 );

21sort( high +1, s2 );

22} // end, if ( si < s2 )

Определение sort() выглядит следующим образом:

23 }

sort() реализует алгоритм быстрой сортировки Хоара (C.A.R.Hoare). Рассмотрим ее определение детально. Она сортирует элементы массива от s1 до s2. Это рекурсивная функция, которая вызывает сама себя для последовательно уменьшающихся подмассивов. Рекурсия окончится тогда, когда s1 и s2 укажут на один и тот же элемент или s1 будет располагаться после s2 (строка 5).

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

366

elem (строка 6) является разделяющим элементом. Все элементы, меньшие чем elem, перемещаются влево от него, а большие вправо. Теперь массив разбит на две части. sort() рекурсивно вызывается для каждой из них (строки 20-21).

Цикл for(;;) проводит разделение (строки 10-17). На каждой итерации цикла индекс low увеличивается до первого элемента, большего или равного elem (строка 11). Аналогично high уменьшается до последнего элемента, меньшего или равного elem (строка 12). Когда low становится равным или большим high, мы выходим из цикла, в

противном случае нужно поменять местами значения элементов и начать новую итерацию (строки 14-16). Хотя элементы разделены, elem все еще остается первым в массиве. swap() в строке 19 ставит его на место до рекурсивного вызова sort() для двух частей массива.

Сравнение производится вызовом функции, на которую указывает compare (строки 1112). Чтобы поменять элементы массива местами, используется операция swap() с аргументами типа string, представленная в разделе 6.11.

#include <iostream> #include <string>

// это должно бы находиться в заголовочном файле int lexicoCompare( const string &, const string & ); int sizeCompare( const string &, const string & );

typedef int (*PFI)( const string &, const string & ); void sort( string *, string *, PFI=lexicoCompare );

string as[10] = { "a", "light", "drizzle", "was", "falling", "when", "they", "left", "the", "museum" };

int main() {

// вызов sort() с значением по умолчанию параметра compare sort( as, as + sizeof(as)/sizeof(as[0]) - 1 );

// выводим результат сортировки

for ( int i = 0; i < sizeof(as)/sizeof(as[0]); ++i ) cout << as[ i ].c_str() << "\n\t";

Вот как выглядит main(), в которой применяется наша функция сортировки:

}

Результат работы программы:

"a"

"drizzle"

"falling"

"left"

"light"

"museum"

"the"

"they"

"was"

"when"

Параметр функции автоматически приводится к типу указателя на функцию: