Чтение онлайн

на главную

Жанры

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

Рассмотрим пример.

Shape ss; // ошибка: невозможно создать объект класса Shape

Класс
Shape
может быть использован только в роли базового класса. В данном случае ничего страшного не произошло бы, если бы мы позволили создавать объекты класса
Shape
непосредственно, но, ограничив его применение, мы открыли возможность его модификации, что было бы невозможно, если бы кто-то мог его использовать непосредственно. Кроме того, запретив прямое создание объектов класса
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
и снабдить операциями, изменяющими точки.

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

Боги, пиво и дурак. Том 3

Горина Юлия Николаевна
3. Боги, пиво и дурак
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Боги, пиво и дурак. Том 3

Мымра!

Фад Диана
1. Мымрики
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Мымра!

Белые погоны

Лисина Александра
3. Гибрид
Фантастика:
фэнтези
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Белые погоны

Любовь Носорога

Зайцева Мария
Любовные романы:
современные любовные романы
9.11
рейтинг книги
Любовь Носорога

Я все еще граф. Книга IX

Дрейк Сириус
9. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я все еще граф. Книга IX

Делегат

Астахов Евгений Евгеньевич
6. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Делегат

Неудержимый. Книга XVI

Боярский Андрей
16. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XVI

Чужая дочь

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Чужая дочь

Ночь со зверем

Владимирова Анна
3. Оборотни-медведи
Любовные романы:
любовно-фантастические романы
5.25
рейтинг книги
Ночь со зверем

Месть бывшему. Замуж за босса

Россиус Анна
3. Власть. Страсть. Любовь
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Месть бывшему. Замуж за босса

Совок – 3

Агарев Вадим
3. Совок
Фантастика:
фэнтези
детективная фантастика
попаданцы
7.92
рейтинг книги
Совок – 3

Титан империи 7

Артемов Александр Александрович
7. Титан Империи
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Титан империи 7

Измена. Он все еще любит!

Скай Рин
Любовные романы:
современные любовные романы
6.00
рейтинг книги
Измена. Он все еще любит!

Вечный Данж. Трилогия

Матисов Павел
Фантастика:
фэнтези
юмористическая фантастика
6.77
рейтинг книги
Вечный Данж. Трилогия