Kniga-Online.club
» » » » Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Читать бесплатно Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп. Жанр: Программирование год 2004. Так же читаем полные версии (весь текст) онлайн без регистрации и SMS на сайте kniga-online.club или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
Перейти на страницу:
draw_lines() const;

  // пусть каждый производный класс

  // сам определяет свою собственную функцию draw_lines(),

  // если это необходимо

  // ...

};

struct Circle : Shape {

  // ...

  void draw_lines() const; // " замещение " функции

  // Shape::draw_lines()

  // ...

};

Итак, функция draw_lines() из класса Shape должна как-то вызывать одну из функций-членов класса Circle, если фигурой является объект класса Shape, и одну из функций-членов класса Rectangle, если фигура является объектом класса Rectangle. Вот что означает слово virtual в объявлении функции draw_lines(): если класс является производным от класса Shape, то он должен самостоятельно объявить свою собственную функцию draw_lines() (с таким же именем, как функция draw_lines() в классе Shape), которая будет вызвана вместо функции draw_lines() из класса. В главе 13 показано, как это сделано в классах Text, Circle, Closed_polyline и т.д. Определение функции в производном классе, используемой с помощью интерфейса базового класса, называют замещением (overriding).

Обратите внимание на то, что, несмотря на свою главную роль в классе Shape, функция draw_lines() находится в разделе protected. Это сделано не для того, чтобы подчеркнуть, что она предназначена для вызова “общим пользователем” — для этого есть функция draw(). Просто тем самым мы указали, что функция draw_lines() — это “деталь реализации”, используемая функцией draw() и классами, производными от класса Shape.

На этом завершается описание нашей графической модели, начатое в разделе 12.2. Система, управляющая экраном, “знает” о классе Window. Класс Window “знает” о классе Shape и может вызывать его функцию-член draw(). В заключение функция draw() вызывает функцию draw_lines(), чтобы нарисовать конкретную фигуру. Вызов функции gui_main() в нашем пользовательском коде запускает драйвер экрана.

Что делает функция gui_main()? До сих пор мы не видели ее в нашей программе. Вместо нее мы использовали функцию wait_for_button(), которая вызывала драйвер экрана более простым способом.

Функция move() класса Shape просто перемещает каждую хранимую точку на определенное расстояние относительно текущей позиции.

void Shape::move(int dx, int dy) // перемещает фигуру +=dx and +=dy

{

  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. Базовые и производные классы

Посмотрим на базовый и производные классы с технической точки зрения; другими словами, в этом

Перейти на страницу:

Бьёрн Страуструп читать все книги автора по порядку

Бьёрн Страуструп - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки kniga-online.club.


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

Отзывы читателей о книге Программирование. Принципы и практика использования C++ Исправленное издание, автор: Бьёрн Страуструп. Читайте комментарии и мнения людей о произведении.


Уважаемые читатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.

  • 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
  • 2. Просьба отказаться от оскорблений, угроз и запугиваний.
  • 3. Просьба отказаться от нецензурной лексики.
  • 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.

Надеемся на Ваше понимание и благоразумие. С уважением, администратор kniga-online.


Прокомментировать
Подтвердите что вы не робот:*
Подтвердите что вы не робот:*