Перейти на главную   
  helloworld.ru - документация и книги по программированию  
helloworld.ru - документация и книги по программированию
    главная     хостинг    
Поиск по сайту:  
Смотрите также
Языки программирования
C#
MS Visual C++
Borland C++
C++ Builder
Visual Basic
Quick Basic
Turbo Pascal
Delphi
JavaScript
Java
PHP
Perl
Assembler
AutoLisp
Fortran
Python
1C

Интернет-технологии
HTML
VRML
HTTP
CGI
FTP
Proxy
DNS
протоколы TCP/IP
Apache

Web-дизайн
HTML
Дизайн
VRML
PhotoShop
Cookie
CGI
SSI
CSS
ASP
PHP
Perl

Программирование игр
DirectDraw
DirectSound
Direct3D
OpenGL
3D-графика
Графика под DOS

Алгоритмы
Численные методы
Обработка данных

Сис. программирование
Драйверы

Базы данных
MySQL
SQL

Другое

Хостинг


Друзья
demaker.ru
Реклама

Лучший хостинг. Аренда серверов




helloworld.ru

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

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

int iVal1;
int iVal2;
iVal1 = 100;
iVal2 = iVal1;

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

Вернёмся к старой версии конструктора (её проще повторно воспроизвести, чем описывать словами) и снова модифицируем main процедуру нашей программы. Мы определяем новый объект, используем операцию присвоения и наблюдаем за результатами:

ComplexType()
{
 real = 0.0;
 imag = 0.0;
 CTcharVal = 0;
 x = 0;
 cout << "Здесь ComplexType() конструктор!" << endl;
}
:::::
void main()
{
 ComplexType CDw1;
 ComplexType CDw2 = CDw1;
 cout << "(" << CDw1.real << ", " << CDw1.imag << "i)" << endl;
 cout << (int)CDw1.CTcharVal << ", " << CDw1.x << "…" << endl;
 cout << "(" << CDw2.real << ", " << CDw2.imag << "i)" << endl;
 cout << (int)CDw2.CTcharVal << ", " << CDw2.x << "…" << endl;
}

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

В программе определяется два объекта. Можно предположить, что у этих объектов окажутся одинаковые значения данных-членов. Было бы странно, если бы результат операции присвоения для основных типов по своему результату отличался бы от операции присвоения для данных производных типов.

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

if (&CDw1 != &CDw2) cout << "OK!" << endl;
                                      /* Сообщить о разных адресах.*/

И всё же выполнение этой тривиальной программы приводит к неожиданному результату: создавая два объекта, мы наблюдаем всего одно сообщение о работе конструктора.

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

Так и есть! Такой конструктор существует и называется конструктором копирования. Вместе с конструктором умолчания, конструктор копирования входит в обязательный набор конструкторов для любого класса. Реализация механизма копирования значений для транслятора не является неразрешимой задачей. Конструктор копирования всего лишь создаёт копии объектов. Этот процесс реализуется при помощи стандартного программного кода. И построить такой код транслятор способен самостоятельно.

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

Подобно конструктору умолчания, конструктор копирования наряду с уже известной нам формой вызова

ComplexType CDw2 = CDw1;

имеет несколько альтернативных, приводящих к аналогичному конечному результату вызовов:

ComplexType CDw2(CDw1);
ComplexType CDw3 = ComplexType(CDw1);

Обе альтернативные формы вызова напоминают нам уже известные формы вызова конструкторов с параметрами. Чтобы восстановить структуру заголовка конструктора копирования, мы должны лишь определить тип его параметра.

На первый взгляд, здесь всё просто. В качестве значения параметра конструктору передаётся имя объекта, значит можно предположить, что тип параметра конструктора копирования соответствует данному классу. Так, в нашем случае, конструктор копирования класса ComplexType должен был бы иметь параметр типа ComplexType. Однако это не так. И вот почему.

В C++ конструктор копирования является единственным средством создания копий объекта.

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

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

Итак, КОНСТРУКТОР КОПИРОВАНИЯ КЛАССА X НЕ МОЖЕТ ИМЕТЬ ПАРАМЕТР ТИПА X. Это аксиома.

На самом деле, в конструкторе копирования класса X в качестве параметра используется ссылка на объект этого класса. Причём эта ссылка объявляется со спецификатором const. И в этом нет ничего странного. Как известно, выражение вызова функции с параметром типа X ничем не отличается от выражения вызова функции, у которой параметром является ссылка на объект типа X. При вызове такой функции не приходится копировать объекты как параметры. Передача адреса не требует копирования объекта, а значит, при этом не будет и рекурсии.

Конструктор копирования - обязательный элемент любого класса. Он также может быть переопределён подобно конструктору умолчания. При этом работа со ссылками в конструкторе копирования не требует явного использования операции разыменования. А спецификатор const (конструктор копирования работает с адресом объекта) предохраняет объект-параметр от случайной модификации в теле конструктора.


[ Назад | Оглавление | Далее ]









helloworld.ru © 2001-2021
Все права защищены