Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

for (int i = 0; i<points.size; ++i) {

points[i].x+=dx;

points[i].y+=dy;

}

}

Подобно функции

draw_lines
, функция
move
является виртуальной, поскольку производный класс может иметь данные, которые необходимо переместить и о которых может “не знать” класс
Shape
. В качестве примера можно привести класс
Axis
(см. разделы 12.7.3 и 15.4).

Функция

move
не является логически необходимой для класса
Shape
; мы ввели ее для удобства и в качестве примера еще одной виртуальной функции. Каждый вид фигуры, имеющей точки, не хранящиеся в базовом классе
Shape
, должен определить свою собственную функцию
move
.

14.2.4. Копирование и изменчивость

Класс Shape содержит закрытые объявления копирующего конструктора (copy constructor) и оператора копирующего присваивания (copy assignment constructor).

private:

Shape(const Shape&); // prevent copying

Shape& operator=(const Shape&);

В результате только члены класса

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

void my_fct(const Open_polyline& op, const Circle& c)

{

Open_polyline op2 = op; // ошибка: копирующий конструктор

// класса Shape закрыт

vector<Shape> v;

v.push_back(c); // ошибка: копирующий конструктор

// класса Shape закрыт

// ...

op = op2; // ошибка: присваивание в классе

// Shape закрыто

}

Однако копирование может быть полезным во многих ситуациях! Просто взгляните на функцию
push_back
; без копирования было бы трудно использовать векторы (функция
push_back
помещает в вектор копию своего аргумента). Почему надо беспокоиться о непредвиденном копировании? Если операция копирования по умолчанию может вызывать проблемы, ее следует запретить. В качестве основного примера такой проблемы рассмотрим функцию
my_fct
. Мы не можем копировать объект класса
Circle
в вектор
v
, содержащий объекты типа
Shape
; объект класса
Circle
имеет радиус, а объект класса
Shape
— нет, поэтому
sizeof(Shape) <sizeof(Circle)
. Если бы мы допустили операцию
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
) в дополнение к своим собственным. Это свойство часто называют наследованием (inheritance), потому что производный класс наследует все члены базового класса. Иногда производный класс называют подклассом (subclass), а базовый — суперклассом (superclass).

  • Читать дальше
  • 1
  • ...
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: