Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

массива, граница первого измерения не учитывается при проверке типов. Если параметры являются многомерными массивами, то контролируются все измерения, кроме первого.

Заметим, что скобки вокруг *matrix необходимы из-за более высокого приоритета операции взятия индекса. Инструкция

int *matrix[10];

объявляет matrix как массив из десяти указателей на int.

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

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

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

#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";

изменить определение нашей putValues() на такое:

}

Функция 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, '#');

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

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

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

невозможно задать значение для background, не задавая его для height и width. 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

<cstdl

ib>

при каждом вызове:

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() еще раз: