Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Липпман.doc
Скачиваний:
7
Добавлен:
14.08.2019
Размер:
7.54 Mб
Скачать

7.3.4. Абстрактные контейнерные типы в качестве параметров

Абстрактные контейнерные типы, представленные в главе 6, также используются для объявления параметров функции. Например, можно определить putValues() как имеющую параметр типа vector<int> вместо встроенного типа массива.

Контейнерный тип является классом и обеспечивает значительно большую функциональность, чем встроенные массивы. Так, vector<int> “знает” собственный размер. В предыдущем подразделе мы видели, что размер параметра-массива неизвестен функции и для его передачи приходится задавать дополнительный параметр. Использование vector<int> позволяет обойти это ограничение. Например, можно изменить определение нашей putValues() на такое:

#include <iostream>

#include <vector>

const lineLength =12; // количество элементов в строке

void putValues( vector<int> vec )

{

cout << "( " << vec.size() << " )< ";

for ( int i = 0; i < vec.size(); ++1 ) {

if ( i % lineLength == 0 && i )

cout << "\n\t"; // строка заполнена

cout << vec[ i ];

// разделитель, печатаемый после каждого элемента,

// кроме последнего

if ( 1 % lineLength != lineLength-1 &&

i != vec.size()-1 )

cout << ", ";

}

cout << " >\n";


}

Функция main(), вызывающая нашу новую функцию putValues(), выглядит так:

void putValues( vector<int> );

int main() {

int i, j[ 2 ];

// присвоить i и j некоторые значения

vector<int> vec1(1); // создадим вектор из 1 элемента

vecl[0] = i;

putValues( vecl );

vector<int> vec2; // создадим пустой вектор

// добавим элементы к vec2

for ( int ix = 0;

ix < sizeof( j ) / sizeof( j[0] );

++ix )

// vec2[ix] == j [ix]

vec2.push_back( j[ix] );

putValues( vec2 );

return 0;


}

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

Как бы вы изменили объявление putValues()?

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

void putValues( const vector<int> & ) { ...

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, '#');

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

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

cursor = screenInit('?');

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


cursor = screenInit( , ,'?');

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

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

// ошибка: 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? Следующая строка ошибочна, поскольку она повторно задает значение для с:

#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() без указания третьего аргумента.