В результате только члены класса Shape могут копировать объекты класса Shape, используя операции копирования, заданные по умолчанию. Это общая идиома, предотвращающая непредвиденное копирование. Рассмотрим пример.
void my_fct(const Open_polyline& op, const Circle& c)
{
Open_polyline op2 = op; // ошибка: копирующий конструктор
// класса Shape закрыт
vector
v.push_back(c); // ошибка: копирующий конструктор
// класса Shape закрыт
// ...
op = op2; // ошибка: присваивание в классе
// Shape закрыто
}
push_back(); без копирования было бы трудно использовать векторы (функция push_back() помещает в вектор my_fct(). Мы не можем копировать объект класса Circle в вектор v, содержащий объекты типа Shape; объект класса Circle имеет радиус, а объект класса Shape — нет, поэтому sizeof(Shape) v.push_back(c), то объект класса Circle был бы “обрезан” и любое последующее использование элемента вектора v привело бы к краху; операции класса Circle предполагают наличие радиуса (члена r), который не был скопирован.
Конструктор копирования объекта op2 и оператор присваивания объекту op имеют тот же самый недостаток. Рассмотрим пример.
Marked_polyline mp("x");
Circle c(p,10);
my_fct(mp,c); // аргумент типа Open_polyline ссылается
// на Marked_polyline
Теперь операции копирования класса Open_polyline приведут к “срезке” объекта mark, имеющего тип string.
Shape.
Срезка (да, это технический термин) — не единственная причина, по которой следует предотвращать копирование. Существует еще несколько понятий, которые лучше представлять без операций копирования. Напомним, что графическая система должна помнить, где хранится объект класса Shape на экране дисплея. Вот почему мы связываем объекты класса Shape с объектами класса Window, а не копируем их. Объект класса Window ничего не знает о копировании, поэтому в данном случае копия действительно хуже оригинала.
clone(). Очевидно, что функцию clone() можно написать, только если функций для чтения данных достаточно для реализации копирования, как в случае с классом Shape.
14.3. Базовые и производные классы
Посмотрим на базовый и производные классы с технической точки зрения; другими словами, в этом разделе предметом дискуссии будет не программирование, проектирование и графика, а язык программирования. Разрабатывая нашу библиотеку графического интерфейса, мы использовали три основных механизма.
Circle является производным от класса Shape, иначе говоря, класс Circle является разновидностью класса Shape или класс Shape является базовым по отношению к классу Circle. Производный класс (в данном случае Circle) получает все члены базового класса (в данном случае Shape) в дополнение к своим собственным. Это свойство часто называют