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

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

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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 140 141 142 143 144 145 146 147 148 ... 337
Перейти на страницу:
открыли возможность его модификации, что было бы невозможно, если бы кто-то мог его использовать непосредственно. Кроме того, запретив прямое создание объектов класса Shape, мы непосредственно моделируем идею о том, что абстрактной фигуры в природе не существует, а реальными являются лишь конкретные фигуры, такие как объекты класса Circle и Closed_polyline. Подумайте об этом! Как выглядит абстрактная фигура? Единственный разумный ответ на такой вопрос — встречный вопрос: какая фигура? Понятие о фигуре, воплощенное в классе Shape, носит абстрактный характер. Это важное и часто полезное свойство, поэтому мы не хотим компрометировать его в нашей программе. Позволить пользователям непосредственно создавать объекты класса Shape противоречило бы нашим представлениям о классах как о прямых воплощениях понятий. Конструктор определяется следующим образом:

Shape::Shape()

      :lcolor(fl_color()),     // цвет линий и символов по умолчанию

      ls(0),                   // стиль по умолчанию

      fcolor(Color::invisible) // без заполнения

{

}

Это конструктор по умолчанию, поэтому все его члены также задаются по умолчанию. Здесь снова в качестве основы использована библиотека FLTK. Однако понятия цвета и стиля, принятые в библиотеке FLTK, прямо не упоминаются. Они являются частью реализации классов Shape, Color и Line_style.

Объект класса vector<Points> по умолчанию считается пустым вектором.

 

 Класс является абстрактным (abstract), если его можно использовать только в качестве базового класса. Для того чтобы класс стал абстрактным, в нем часто объявляют чисто виртуальную функцию (pure virtual function), которую мы рассмотрим в разделе 14.3.5. Класс, который можно использовать для создания объектов, т.е. не абстрактный класс, называется конкретным (concrete). Обратите внимание на то, что слова абстрактный и конкретный часто используются и в быту. Представим себе, что мы идем в магазин покупать фотоаппарат. Однако мы не можем просто попросить какой-то фотоаппарат и принести его домой. Какую торговую марку вы предпочитаете? Какую модель фотоаппарата хотите купить? Слово фотоаппарат — это обобщение; оно ссылается на абстрактное понятие. Название “Olympus E-3” означает конкретную разновидность фотоаппарата, конкретный экземпляр которого с уникальным серийным номером мы можем купить (в обмен на большую сумму денег). Итак, фотоаппарат — это абстрактный (базовый) класс, “Olimpus E-3” — конкретный (производный) класс, а реальный фотоаппарат в моей руке (если я его купил) — это объект.

Объявление

virtual ~Shape() { }

определяет виртуальный деструктор. Мы не будем пока его использовать и рассмотрим позднее, в разделе 17.5.2. 

14.2.2. Управление доступом

Класс Shape объявляет все данные-члены закрытыми.

private:

  vector<Point> points;

  Color lcolor;

  Line_style ls;

  Color fcolor; 

 

 Поскольку данные-члены класса Shape объявлены закрытыми, нам нужно предусмотреть функции доступа. Существует несколько стилей решения этой задачи. Мы выбрали простой, удобный и понятный. Если у нас есть член, представляющий свойство X, то мы предусмотрели пару функций, X() и set_X(), для чтения и записи соответственно. Рассмотрим пример.

void Shape::set_color(Color col)

{

  lcolor = col;

}

Color Shape::color() const

{

  return lcolor; 

}

Основной недостаток этого стиля заключается в том, что мы не можем назвать переменную так же, как функцию для ее чтения. Как всегда, мы предпочли выбрать наиболее удобные имена для функций, поскольку они являются частью открытого интерфейса. Как назвать закрытые переменные, менее важно. Обратите внимание на то, что мы использовали ключевое слово const, чтобы подчеркнуть, что функция чтения не может модифицировать члены своего класса Shape (см. раздел 9.7.4).

В классе Shape хранится вектор объектов класса Point с именем points, которые предназначены для его производных классов. Для добавления объектов класса Point в вектор points предусмотрена функция add().

void Shape::add(Point p) // защищенный

{

  points.push_back(p);

}

Естественно, сначала вектор points пуст. Мы решили снабдить класс Shape полным функциональным интерфейсом, а не предоставлять функциям-членам классов, производных от класса Shape, прямого доступа к его данным-членам. Одним людям создание функционального интерфейса кажется глупым, поскольку они считают, что недопустимо делать какие-либо данные-члены класса открытыми. Другим наш подход кажется слишком узким, потому что мы не разрешаем членам производных классов прямой доступ к членам базового класса.

Классы, производные от класса Shape, например Circle и Polygon, “понимают”, что означают их точки. Базовый класс Shape этого “не понимает”, он просто хранит точки. Следовательно, производные классы должны иметь контроль над тем, как добавляются точки. Рассмотрим пример.

• Классы Circle и Rectangle не позволяют пользователю добавлять точки, они просто “не видят” в этом смысла. Что такое прямоугольник с дополнительной точкой? (См. раздел 12.7.6.)

• Класс Lines позволяет добавлять любые пары точек (но не отдельные точки; см. раздел 13.3).

• Классы Open_polyline и Marks позволяют добавлять любое количество точек.

• Класс Polygon позволяет добавлять точки только с помощью функции add(), проверяющей пересечения (раздел 13.8).

 

 Мы поместили функцию add() в раздел protected (т.е. сделали ее доступной только для производных классов), чтобы гарантировать, что производные классы смогут управлять добавлением точек. Если бы функция add() находилась в разделе public (т.е. каждый класс мог добавлять точки) или private (только класс Shape мог добавлять точки), то такое точное соответствие функциональных возможностей нашему представлению о фигуре стало бы невозможным.

По аналогичным причинам мы поместили функцию set_point() в класс protected. В общем, только производный класс может “знать”, что означают точки и можно ли их изменять, не нарушая инвариант.

Например, если класс Regular_hexagon объявлен как множество, состоящее из шести точек, то изменение даже одной точки может породить фигуру, не являющуюся правильным шестиугольником. С другой стороны, если мы изменим одну из точек прямоугольника, то в результате все равно получим прямоугольник. Фактически функция set_point() в этом случае оказывается ненужной, поэтому мы включили ее просто для того, чтобы обеспечить выполнение правил чтения и записи каждого атрибута класса Shape. Например, если бы мы захотели создать класс Mutable_rectangle, то могли бы вывести его из класса Rectangle и снабдить операциями, изменяющими точки.

Мы поместили вектор points объектов класса

1 ... 140 141 142 143 144 145 146 147 148 ... 337
Перейти на страницу:
На этой странице вы можете бесплатно скачать Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп торрент бесплатно.
Комментарии
КОММЕНТАРИИ 👉
Комментарии
Мишель
Мишель 31.01.2025 - 12:20
Книга очень понравилась. Интригующий сюжет 
Аннушка
Аннушка 16.01.2025 - 09:24
Следите за своим здоровьем  книга супер сайт хороший
Татьяна
Татьяна 21.11.2024 - 19:18
Одним словом, Марк Твен!
Без носенко Сергей Михайлович
Без носенко Сергей Михайлович 25.10.2024 - 16:41
Я помню брата моего деда- Без носенко Григория Корнеевича, дядьку Фёдора т тётю Фаню. И много слышал от деда про Загранное, Танцы, Савгу...