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

a + b;

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

Представим себе, что мы решили использовать указатели в качестве параметров, чтобы избежать этих затрат. Вот модифицированный код operator+():

// реализация с параметрами-указателями

operator+( Matrix *ml, Matrix *m2 )

{

Matrix result;

// необходимые действия

return result;

}

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

a + b; // допустимо, хотя и плохо

Хотя такая форма не может не вызвать критику, но все-таки два объекта сложить еще удается. А вот три уже крайне затруднительно:

// а вот это не работает

// a + b возвращает объект типа Matrix

a + b + c;

Для того чтобы сложить три объекта, при подобной реализации нужно написать так:

// правильно: работает, однако ...

( a + b ) + c;

Трудно ожидать, что кто-нибудь согласится писать такие выражения. К счастью, параметры-ссылки дают именно то решение, которое требуется. Если параметр объявлен как ссылка, функция получает его l-значение, а не копию. Лишнее копирование исключается. И тип фактического аргумента может быть Matrix – это упрощает операцию сложения, как и для встроенных типов. Вот схема перегруженного оператора сложения для класса Matrix:

// реализация с параметрами-ссылками

operator+( const Matrix m1, const Matrix m2 )

{

Matrix result;

// необходимые действия

return result;

}

При такой реализации сложение трех объектов Matrix выглядит вполне привычно:

a + b + c;

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

7.3.3. Параметры-массивы

Массив в С++ никогда не передается по значению, а только как указатель на его первый, точнее нулевой, элемент. Например, объявление

void putValues( int[ 10 ] );

рассматривается компилятором так, как будто оно имеет вид

void putValues( int* );

Размер массива неважен при объявлении параметра. Все три приведенные записи эквивалентны:

// три эквивалентных объявления putValues()

void putValues( int* );

void putValues( int[] );

void putValues( int[ 10 ] );

Передача массивов как указателей имеет следующие особенности:

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

void putValues( const int[ 10 ] );

*

размер массива не является частью типа параметра. Поэтому функция не знает реального размера передаваемого массива. Компилятор тоже не может это проверить. Рассмотрим пример:

void putValues( int[ 10 ] ); // рассматривается как int*

int main() {

int i, j [ 2 ];

putValues( i ); // правильно: i is int*;

// однако при выполнении возможна ошибка

putValues( j ); // правильно: j - адрес 0-го элемента - int*;

// однако при выполнении возможна ошибка

*

При проверке типов параметров компилятор способен распознать, что в обоих случаях тип аргумента int* соответствует объявлению функции. Однако контроль за тем, не является ли аргумент массивом, не производится.

По принятому соглашению C-строка является массивом символов, последний элемент которого равен нулю. Во всех остальных случаях при передаче массива в качестве параметра необходимо указывать его размер. Это относится и к массивам символов, внутри которых встречается 0. Обычно для такого указания используют дополнительный параметр функции. Например:

void putValues( int[], int size );

int main() {

int i, j[ 2 ];

putValues( i, 1 );

putValues( j, 2 );