Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа № 6Ссылка, перегрузка.doc
Скачиваний:
5
Добавлен:
13.09.2019
Размер:
103.94 Кб
Скачать

9

Лабораторная работа № 6

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

Передача функции аргументов по ссылке

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

Задание 1. Передача данных по значению

#include <vcl.h>

# include <iostream.h>

#include <conio.h>

using namespace std;

void swap(int x, int y);

int main(int argc, char* argv[])

{ int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: "

<< y << "\n";

swap(x,y);

cout << "Main. After swap, x: " << x << " y: "

<< y << "\n";

getch();

return 0;

}

void swap(int x, int y)

{

int temp;

cout << "Swap. Before swap, x: " << x << " y: "

<< y << "\n";

temp = x;

x = y;

y = temp;

cout << "Swap. After swap, x: " << x << " y: "

<< y << "\n";

}

Эта программа инициализирует в функции main() две переменные, а затем переда­ет их функцииswap(), которая, казалось бы, должна поменять их значения. Но переменные х и у, переданные функции swap(), по значению, являются локальными копиями этих переменных, созданных непосредственно в функции. Чтобы решить проблему, необходимо передать значения переменных x и y по ссылке. В языке С++ передача данных по ссылке осуществляется двумя способами: с помощью указателей и с помощью ссылок.

Задание 2. Передача данных по ссылке с помощью указателей

#include <vcl.h>

# include <iostream.h>

#include <conio.h>

using namespace std;

void swap(int* x, int* y);

int main(int argc, char* argv[])

{ int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: "

<< y << "\n";

swap(&x,&y); //Передаются адреса переменных

cout << "Main. After swap, x: " << x << " y: "

<< y << "\n";

getch();

return 0;

}

void swap(int* px, int* py)

{

int temp;

cout << "Swap. Before swap, *px: " << *px << " *py: "

<< *py << "\n";

temp = *px;

*px = *py;

*py = temp;

cout << "Swap. After swap, *px: " << *px << " y: "

<< *py << "\n";

}

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

Задание 3. Передача данных по ссылке с помощью ссылки

#include <vcl.h>

# include <iostream.h>

#include <conio.h>

using namespace std;

void swap(int& x, int& y);

int main(int argc, char* argv[])

{ int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: "

<< y << "\n";

swap(x,y);

cout << "Main. After swap, x: " << x << " y: "

<< y << "\n";

getch();

return 0;

}

void swap(int& rx, int& ry)

{

int temp;

cout << "Swap. Before swap, rx: " << rx << " ry: "

<< ry << "\n";

temp = rx;

rx = ry;

ry = temp;

cout << "Swap. After swap, rx: " << rx << " y: "

<< ry << "\n";

}

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

При каждой передаче объекта в функцию как значения создается копия этого объ­екта. При каждом возврате объекта из функции

создается еще одна копия. Эти объекты копируются в стек, и на этот процесс расходуется время и память. Для таких маленьких

объектов, как встро­енные целочисленные значения, цена этих расходов незначительна. Но для больших пользовательских

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

При работе с большими объектами постоянные вызовы конструктора и деструкто­ра могут оказать ощутимое влияние на скорость работы программы и использование памяти компьютера. Для подтверждения этой идеи в листинге задания 4 создается пользовательский объект SimplеCat, после чего вызываются две функ­ции. Первая функция принимает объект Саt как значение, а затем возвращает его как значение. Вторая же функция принимает не сам объект, а лишь указатель на него, и возвращает также указатель. Реальный объект имел бы большие размеры и занял бы больше памяти, но и этого примера вполне достаточно, чтобы показать, насколько часто вызываются конструктор копий и деструктор.

Задания 4. Демонстрация вызова конструктора копий

#include <vcl.h>

# include <iostream.h>

#include <conio.h>

using namespace std;

class SimpleCat

{

public:

SimpleCat (); // Конструктор

SimpleCat (SimpleCat &); // Конструктор копий

~SimpleCat(); // Деструктор

};

SimpleCat::SimpleCat()

{

cout << " Constructor... \n";

}

SimpleCat::SimpleCat (SimpleCat&)

{

cout << " * Copy Constructor... \n";

}

SimpleCat:: ~SimpleCat()

{

cout << " Destructor... \n";

}

SimpleCat FunctionOne (SimpleCat theCat);

SimpleCat* FunctionTwo (SimpleCat* theCat);

int main(int argc, char* argv[])

{

cout << "Making a cat...\n";

SimpleCat Frisky;

cout << " Calling FunctionOne... \n";

FunctionOne(Frisky);

cout << " Calling FunctionTwo... \n";

FunctionTwo(&Frisky);

cout << " Calling FunctionOne... \n";

FunctionOne(Frisky);

getch();

return 0;

}

SimpleCat FunctionOne (SimpleCat theCat)

{

cout << " Function One.Returning... \n";

return theCat;

}

SimpleCat* FunctionTwo (SimpleCat* theCat)

{

cout << " Function Two.Returning... \n";

return theCat;

}