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

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

334

7.3.5. Значения параметров по умолчанию

Значение параметра по умолчанию это значение, которое разработчик считает подходящим в большинстве случаев употребления функции, хотя и не во всех. Оно

освобождает программиста от необходимости уделять внимание каждой детали интерфейса функции.

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

char *screenInit( int height = 24, int width = 80,

фона экрана:

char background = ' ' );

Функция, для которой задано значение параметра по умолчанию, может вызываться по- разному. Если аргумент опущен, используется значение по умолчанию, в противном случае значение переданного аргумента. Все следующие вызовы screenInit()

char *cursor;

//эквивалентно screenInit(24,80,' ') cursor = screenInit();

//эквивалентно screenInit(66,80,' ') cursor = screenlnit(66);

//эквивалентно screenInit(66,256,' ') cursor = screenlnit(66, 256);

корректны:

cursor = screenlnit(66, 256, '#');

Фактические аргументы сопоставляются с формальными параметрами позиционно (в порядке следования), и значения по умолчанию могут использоваться только для подстановки вместо отсутствующих последних аргументов. В нашем примере

//эквивалентно screenInit('?',80,' ') cursor = screenInit('?');

//ошибка, неэквивалентно screenInit(24,80,'?')

невозможно задать значение для background, не задавая его для height и width. cursor = screenInit( , ,'?');

При разработке функции с параметрами по умолчанию придется позаботиться об их расположении. Те, для которых значения по умолчанию вряд ли будут употребляться, необходимо поместить в начало списка. Функция screenInit() предполагает (возможно, основываясь на опыте применения), что параметр height будет востребован пользователем наиболее часто.

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

335

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

//ошибка: width должна иметь значение по умолчанию,

//если такое значение имеет height

char *screenlnit( int height = 24, int width,

указаны.

char background = ' ' );

Значение по умолчанию может указываться только один раз в файле. Следующая запись

// tf.h

int ff( int = 0 );

// ft.С #include "ff.h"

ошибочна:

int ff( int i = 0) { ... } // ошибка

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

Можно объявить функцию повторно и таким образом задать дополнительные параметры по умолчанию. Это удобно при настройке универсальной функции для конкретного приложения. Скажем, в системной библиотеке 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? Следующая строка ошибочна, поскольку она повторно задает значение для с:

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

336

#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 расположен правее других, не имеющих значения по умолчанию. Поэтому требование присваивать такие

#include "ff.h"

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

значения справа налево не нарушается. Теперь мы можем переобъявить ff() еще раз: 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( ... );

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

337

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

Примером вынужденного использования многоточия служит функция 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

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

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

338

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

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

(d)

char *screenInit(

int height

= 24, int width,

 

char

background

);

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

(e)void putValues( int (&ia)[] );

Упражнение 7.5

(a) char *screenInit( int height, int width, char background = ' ' );

char *screenInit( int height = 24, int width, char background );

(b)void print( int (*arr)[6], int size ); void print( int (*arr)[5], int size );

(c)void manip( int *pi, int first, int end = 0 );

Повторные объявления всех приведенных ниже функций содержат ошибки. Найдите их. void manip( int *pi, int first = 0, int end = 0 );

Упражнение 7.6

void print( int arr[][5], int size ); void operate(int *matrix[7]);

char *screenInit( int height = 24, int width = 80,

Даны объявления функций.

char background = ' ' );

(a)screenInit();

(b)int *matrix[5]; operate( matrix );

(c)int arr[5][5];

Вызовы этих функций содержат ошибки. Найдите их и объясните. print( arr, 5 );

Упражнение 7.7

Перепишите функцию putValues( vector<int> ), приведенную в подразделе 7.3.4, так, чтобы она работала с контейнером list<string>. Печатайте по одному значению на строке. Вот пример вывода для списка из двух строк:

( 2 )