Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
14
Добавлен:
17.04.2015
Размер:
28.48 Кб
Скачать

7. Чего нельзя делать со ссылками.

По сути ссылка — это указатель, который обязательно при создании ини-циализировать каким-то значением;

нельзя изменять после этого.

Например, вот так написать вообще нельзя:

int &x;

Ссылку обязательно инициализировать! Подойдёт любой из следующих способов:

int z;

int *pz = &z;

int &x1 = z;

int &x2 = *pz;

int &x3 = * (int*) malloc (sizeof (int)); /* но это извращение */

int &x4 = *new int; /* точно такое же извращение */

int &x5 = x1; /* можно инициализировать и через другую ссылку */

/* Следует понимать, что x3, x4 инициализированны динамически.

Память не будет освобождена автоматически, в отличии от других случаев.

Это нужно будет сделать вручную. */

Ссылку, как только что было сказано, нельзя заставить ссылаться на другой объект. Раз уж она начала на что-то ссылаться, то она будет на это ссылаться до конца жизни. Например, заведём указатель и ссылку и попытаемся их поменять:

int z = 3, zz = 5;

int *pz = &z; /* теперь pz указывает на z, *pz == z == 3 */

int &x = z; /* теперь x указывает на z, x == z == 3 */

pz = &zz; /* теперь pz указывает на zz, *pz == zz == 5 */

x = zz; /* но x ведь указывала на z! значит, мы написали «z = zz».

теперь x == z == zz == 5 */

Изменить указатель, скрытый за ссылкой x, нельзя — просто нет в Си++ опера-тора, позволяющего это сделать.

Ещё одно важное отличие — ссылка не может ссылаться «ни на что». То есть, если указатель может иметь значение NULL, то ссылка — нет.

Разве что мы специально постараемся...:

int& g = *(int*)(0);

int* h = &g; /* h == 0 */

g = 2; /* Ошибка выполнения */

Не бывает массивов ссылок и указателей на ссылки — такое не предусмотрено синтаксисом языка Си++.

Если ссылка есть поле класса, то класс обязан иметь явно написанный конст-руктор, и все такие поля обязаны быть инициализированы в ctor-нициализаторе:

int i;

class Ref

{

public:

Ref() : m_r(i) {}

private:

int& m_r;

};

Неконстантная ссылка на тип T может быть инициализирована только lvalue, и только типа T — запрещены даже простейшие преобразования типа short в long и Derived к Base.

Показанное ниже неверно:

Derived d;

Base& br = d; // требуется приведение

short i;

long& ri = i; // требуется приведение

long& lr = 1; // не есть lvalue

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

Derived d;

const Base& cbr = d; // работает

На деле это означает:

Derived d;

Base __tmp1 = d;

const Base& cbr = __tmp1;

Таким образом, ссылки нужны для изменения значения параметра;

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

void f(Monster x);

void g(const Monster& x);

...

Monster barmaley;

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

g(barmaley); // Функция получит адрес barmaley. Kопию создавать не надо.

По этой причине параметры длинее 8 байтов почти всегда передаются по ссылке.

Ссылки и массивы.

Ссылки полезны и в циклах по элементам массива.

for (int i = 0; i < 10; i ++)

{

double& x = a[i];

if (x > 1)

x = 1;

if (x < 0)

x = 0;

x = x * x;

}

Во всех этих случаях можно было бы использовать указатель, и в Си так и делается, но, как сказано выше, указатели опасны. К тому же писать звёздочки и амперсанды — утомительно.

Но по-настоящему необходимы ссылки для перегрузки операторов, о которой пойдёт речь в следующих разделах. Так, например, что ++ обычно понимается как изменяющая свой аргумент, потому ::operator++(T) обычно обязана иметь ссылку в параметре — т.е. ::operator++(T&)

Точно так же operator[] обычно понимается как возвращающая lvalue, что требует T& Arr::operator[](int index);