- •Глава 12
- •Конструкторы и деструкторы. Список инициализации элементов
- •Конструкторы по умолчанию и конструкторы копирования
- •Указатель this
- •Встраиваемые (inline-) функции
- •Статические члены класса
- •Использование указателей на функции-члены класса
- •Массивы объектов класса
- •Дружественные функции и друзья класса
- •Глава 13
- •Множественное наследование
- •Виртуальные базовые классы
- •Глава 14
- •Перегрузка функций
- •Перегрузка конструкторов
- •Создание и использование конструкторов копирования
- •Определение адреса перегруженной функции
Конструкторы по умолчанию и конструкторы копирования
C++ определяет два специальных вида конструкторов: конструктор по умолчанию, о котором мы упоминали выше, и конструктор копирования. Конструктор по умолчанию не имеет параметров (или все его параметры должны иметь значения по умолчанию) и вызывается при создании объекта, которому не заданы аргументы. Следует избегать двусмысленности при вызове конструкторов. В приведенном ниже примере два конструктора по умолчанию являются двусмысленными:
class Т
{
public:
//Конструктор по умолчанию
Т();
//Конструктор c одним параметром;
//может быть использовал как конструктор по умолчанию
Т (int I=0);
};
int main ()
{
Т ob1(10) ;//Использует Т:: Т (int)
Т оb2; //Не верно; неоднозначность вызова. Т: :Т() или Т:: Т (int =0)
return 0;
}
В данном случае, чтобы устранить неоднозначность, достаточно удалить из объявления класса конструктор по умолчанию.
Конструктор копирования (или конструктор копии) создает объект класса, копируя при этом данные из уже существующего объекта данного класса. В связи с этим он имеет в качестве единственного параметра константную ссылку на объект класса (const T&) или просто ссылку на объект класса (T&). Использование первого предпочтительнее, так как последний не позволяет копировать константные объекты. Приведем пример использования конструктора копирования:
class Coord
{
int x, y;
public:
//Конструктор копирования
Coord(const Coord& src);
};
Coord::Coord(const Coord& src)
{
x = src.x;
у = src.у;
}
int main()
{
Coord ob1(2,9);
Coord ob2 = ob1;
Coord ob3(obl);
//...
return 0;
}
Ссылка передается всякий раз, когда новый объект инициализируется значениями существующего. Если вы не предусмотрели конструктор копирования, компилятор генерирует конструктор копирования по умолчанию. В C++ различают поверхностное и глубинное копирование данных. При поверхностном копировании происходит передача только адреса от одной переменной к другой, в результате чего оба объекта указывают на одни и те же ячейки памяти. В случае глубинного копирования происходит действительное копирование значений всех переменных из одной области памяти в другую. Конструктор копирования по умолчанию, созданный компилятором, создает буквальную (или побитную) копию объекта, то есть осуществляет поверхностное копирование. Полученная копия объекта скорее всего будет непригодной, если она содержит указатели или ссылки. Действительно, если эти указатели или ссылки ссылаются на динамически распределенные объекты или на объекты, встроенные в копируемый объект, они будут недоступны в созданной копии объекта. Поэтому для классов, содержащих указатели и ссылки, следует включать в определение класса конструктор копирования, который будет осуществлять глубинное копирование, не полагаясь на создаваемый компилятором конструктор копирования по умолчанию. В этом конструкторе, как правило, выполняется копирование динамических структур данных, на которые указывают или на которые ссылаются члены класса. Класс должен содержать конструктор копирования, если он перегружает оператор присваивания.
Если в классе не определен конструктор, компилятор пытается сгенерировать собственный конструктор по умолчанию и, если нужно, собственный конструктор копирования. Эти сгенерированные компилятором конструкторы рассматриваются как открытые функции-члены. Подчеркнем, что компилятор генерирует эти конструкторы, если в классе не определен никакой другой конструктор.
Сгенерированный компилятором конструктор по умолчанию создает объект и вызывает конструкторы по умолчанию для базовых классов и членов-данных, но не предпринимает никаких других действий. Конструкторы базового класса и членов-данных вызываются, только если они существуют, доступны и являются недвусмысленными. Когда конструируется объект производного класса, конструирование начинается с объектов его базовых классов и продвигается вниз по иерархии классов, пока не будет создан заданный объект. Подробнее этот вопрос будет рассмотрен в следующей главе.
Сгенерированный компилятором конструктор копирования создает новый объект и выполняет почленное копирование содержимого исходного объекта. Если существуют конструкторы базового класса или члена-класса, — они вызываются; иначе выполняется побитное копирование. Если все базовые классы и классы членов-данных класса имеют конструкторы копирования, которые воспринимают const-аргумент, то сгенерированный компилятором конструктор копирования воспринимает аргумент типа const T&. В противном случае он воспринимает аргумент типа Т& (без const).
