Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция_03_КОНСТРУКТОРЫ И ДЕСТРУКТОРЫ.doc
Скачиваний:
4
Добавлен:
11.11.2019
Размер:
91.65 Кб
Скачать

Конструкторы по умолчанию

Конструктор по умолчанию не имеет параметров (или все его параметры должны иметь значения по умолчанию) и вызывается при создании объекта, которому не заданы аргументы. Следует избегать двусмысленности при вызове конструкторов. В приведенном ниже примере два конструктора по умолчанию являются двусмысленными:

Пример 7.

class Т

{

public:

Т(); // конструктор по умолчанию

Т(int i=0); // конструктор с одним необязательным параметром

// может быть использован как конструктор по умолчанию

};

void main()

{

Т оb1(10); // Использует конструктор T::T(int)

Т оb2; // Не верно; неоднозначность вызова Т::Т() или Т::Т(int=0)

}

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

Конструкторы копирования

Конструктор копирования создает объект класса, копируя при этом данные из уже существующего объекта данного класса. В связи с этим он имеет в качестве единственного параметра константную ссылку на объект класса (const Т&) или просто ссылку на объект класса (Т&). Использование первого предпочтительнее, так как последний не позволяет копировать константные объекты.

Пример 8.

class Coord;

{

double x, y; // координаты точки

public:

// конструктор копирования

Coord (const Coord& src);

};

Coord :: Coord (const Coord& src)

{

x=src.x;

y=src.y;

}

void main()

{

Coord ob1(2,9);

Coord ob2=ob1;

Coord ob2(ob1);

}

Ссылка передается всякий раз, когда новый объект инициализируется значениями существующего объекта. Если вы не предусмотрели конструктор копирования, компилятор генерирует конструктор копирования по умолчанию. В C++ различают поверхностное и глубинное копирование данных.

При поверхностном копировании происходит передача только адреса от одной переменной к другой, в результате чего оба объекта указывают на одни и те же ячейки памяти. Конструктор копирования по умолчанию, созданный компилятором, создает буквальную (или побитную) копию объекта, то есть осуществляет поверхностное копирование. Полученная копия объекта, скорее всего, будет непригодной, если она содержит указатели или ссылки.

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

Если в классе не определен конструктор, компилятор пытается сгенерировать собственный конструктор по умолчанию и, если нужно, собственный конструктор копирования. Эти сгенерированные компилятором конструкторы рассматриваются как открытые функции-члены. Подчеркнем, что компилятор генерирует эти конструкторы, если в классе не определен никакой другой конструктор.

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

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

Пример 9.

class Dot // класс точки

{

char name; // имя точки

double x, y; // координаты точки

public: // открытые члены класса

// конструкторы с параметрами

Dot(char Name, double X, double Y)

{

name=Name;

x=X;

y=Y;

}

Dot(char Name):name(Name), x(0), y(0){}

Dot(char Name, const Dot& A)

{

name=Name;

x=A.x;

y=A.y;

}

// конструктор копирования

Dot(const Dot& A)

{

name=(char)226; // переменная принимает значение буквой 'т'

x=A.x;

y=A.y;

}

void Print(); // выводит на экран имя и координаты текущей точки

};

void main()

{

Dot A('A', 3, 4); // вызов конструктора Dot(char Name, double X, double Y)

Dot B('B'); // вызов конструктора Dot (char Name)

Dot C(A); // вызов конструктора копирования Dot (const Dot& A)

C.Print(); // выводит на экран: Координаты точки т: x=3 y=4

Dot D=B; // вызов конструктора копирования Dot (const Dot& A)

D.Print(); // выводит на экран: Координаты точки т: x=0 y=0

Dot E('E', A); // вызов конструктора Dot (char Name ,const Dot& A)

E.Print(); // выводит на экран: Координаты точки E: x=3 y=4

}

Конструктор копирования по умолчанию выполняет поверхностное копирование, которое в нашей задаче копирует не только координаты, но и имена точки. Хотя наш объект не содержит динамических членов-данных, такое копирование нас не устраивает, поскольку мы хотим, чтобы каждая точка имела уникальное имя и не изменяла его в ходе выполнения программы.

В приведённом примере точки C и D объявлены с помощью конструктора копирования объявленного нами. В этом конструкторе имя точки инициализируется фиксированным значением – русской буквой 'т'.

Для решения этой задачи в приведённом примере объявлен конструктор:

Dot (char Name, const Dot& A) {name=Name; x=A.x ; y=A.y;}

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

состояние объекта.

9