Выбрать главу

Можно объявить функцию повторно и таким образом задать дополнительные параметры по умолчанию. Это удобно при настройке универсальной функции для конкретного приложения. Скажем, в системной библиотеке UNIX есть функция chmod(), изменяющая режим доступа к файлу. Ее объявление содержится в системном заголовочном файле cstdlib:

int chmod( char *filePath, int protMode );

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

#include cstdlib

int chmod( char *filePath, int protMode=0444 );

Если функция объявлена в заголовочном файле так:

file int ff( int a, int b, int с = 0 ); // ff.h

то как переобъявить ее, чтобы присвоить значение по умолчанию для параметра b? Следующая строка ошибочна, поскольку она повторно задает значение для с:

#include "ff.h"

int ff( int a, int b = 0, int с = 0 ); // ошибка

Так выглядит правильное объявление:

#include "ff.h"

int ff( int a, int b = 0, int с ); // правильно

В том месте, где мы переобъявляем функцию ff(), параметр b расположен правее других, не имеющих значения по умолчанию. Поэтому требование присваивать такие значения справа налево не нарушается. Теперь мы можем переобъявить ff() еще раз:

#include "ff.h"

int ff( int a, int b = 0, int с ); // правильно

int ff( int a = 0, int b, int с ); // правильно

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

int aDefault();

int bDefault( int );

int cDefault( double = 7.8 );

int glob;

int ff( int a = aDefault() ,

int b = bDefau1t( glob ) ,

int с = cDefault() );

Если такое значение является выражением, то оно вычисляется во время вызова функции. В примере выше cDefault() работает каждый раз, когда происходит вызов функции ff() без указания третьего аргумента.

7.3.6. Многоточие

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

void foo( parm_list, ... );

void foo( ... );

Первый формат предоставляет объявления для части параметров. В этом случае проверка типов для объявленных параметров производится, а для оставшихся фактических аргументов – нет. Запятая после объявления известных параметров необязательна.

Примером вынужденного использования многоточия служит функция printf() стандартной библиотеки С. Ее первый параметр является C-строкой:

int printf( const char* ... );

Это гарантирует, что при любом вызове printf() ей будет передан первый аргумент типа const char*. Содержание такой строки, называемой форматной, определяет, необходимы ли дополнительные аргументы при вызове. При наличии в строке формата метасимволов, начинающихся с символа %, функция ждет присутствия этих аргументов. Например, вызов

printf( "hello, world\n" );

имеет один строковый аргумент. Но

printf( "hello, %s\n", userName );

имеет два аргумента. Символ % говорит о наличии второго аргумента, а буква s, следующая за ним, определяет его тип – в данном случае символьную строку.

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

Отметим, что следующие объявления неэквивалентны:

void f();

void f( ... );

В первом случае f() объявлена как функция без параметров, во втором – как имеющая ноль или более параметров. Вызовы

f( someValue );

f( cnt, a, b, с );

корректны только для второго объявления. Вызов

f();

применим к любой из двух функций.

Упражнение 7.4

Какие из следующих объявлений содержат ошибки? Объясните.

(a) void print( int arr[][], int size );

(b) int ff( int a, int b = 0, int с = 0 );

(c) void operate( int *matrix[] );