Программирование >>  Инициализация объектов класса, структура 

1 ... 106 107 108 [ 109 ] 110 111 112 ... 395


class Type { };

void operate( const Types p1, const Types p2 );

int main() { Type obj1;

присвоим objl некоторое значение

ошибка: ссылка не может быть равной 0 Type obj2 = operate( objl, 0 );

объект. Например:

Если параметр должен ссылаться на разные объекты во время выполнения функции или принимать нулевое значение (ни на что не ссылаться), нам следует использовать указатель.

Одна из важнейших сфер применения параметров-ссылок - эффективная реализация перегруженных операций. При этом использование операций остается простым и интуитивно понятным. (Подробнее данный вопрос рассматривается в главе 15.) Разберем маленький пример. Представим себе класс Matrix (матрица). Хорошо бы реализовать

Matrix a, b, c;

операции сложения и присваивания привычным способом:

c = a + b;

Эти операции реализуются с помощью перегруженных операторов - функций с немного необычным именем. Для оператора сложения такая функция будет называться

Matrix тип возврата - Matrix

operator+( имя перегруженного оператора

Matrix m1, тип левого операнда

Matrix m2 тип правого операнда

Matrix result; необходимые действия return result;

operator+. Посмотрим, как ее определить:

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

a + b;

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

Параметр-ссылка не нуждается в этой проверке, так как всегда существует именуемый ею



реализация с параметрами-указателями operator+( Matrix *ml, Matrix *m2 ) {

Matrix result; необходимхе действия return result;

избежать этих затрат. Вот модифицированный код operator+() :

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

&a + &b; допустимо, хотя и плохо Хотя такая форма не может не вызвать критику, но все-таки два объекта сложить еще

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

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

удается. А вот три уже крайне затруднительно:

&a + &b + &c;

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

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

&( &a + &b ) + &c;

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

реализация с параметрами-сс1лками operator+( const Matrix &m1, const Matrix &m2 )

Matrix result;

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

return result;

сложения для класса Matrix:

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

Представим себе, что мы решили использовать указатели в качестве параметров, чтобы



/ / три эквивалентн1х объявления 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( si ); правильно: si is int*;

однако при выполнении возможна ошибка putValues( j ); правильно: j - адрес 0-го элемента - int*;

проверить. Рассмотрим пример:

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

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

a + b + c;

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

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

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

void putValues( int[ 10 ] );

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

void putValues( int* );

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



1 ... 106 107 108 [ 109 ] 110 111 112 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика