Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 87 88 89 [ 90 ] 91 92 93 ... 144


Инициализаторы членов и базовых классов

В первоначальном определении С++ не требовалось, да и не разрешалось именовать базовый класс в инициализаторе. Например, если есть класс vector:

class vector { ...

vector(lnt);

to можно произвести от него другой класс vec:

class vec : public vector { ...

vec(int,int);

Конструктор класса vec должен вызывать конструктор vector:

vec::vec(int low, int high)

: (high-low-1) аргумент для конструктора базового класса

...

Данная нотация была причиной путаницы.

Явное использование имени базового класса, как требует версия 2.0, сделала запись достаточно прозрачной даже для неискушенных пользователей:

vec::vec(int low, int high) : vector(high-low-1) {

...

Я считаю, что первоначальный вариант является классическим примером синтаксиса логичного, минимального и слишком лаконичного. Проблемы, которые возникали при изложении студентам темы инициализации базовых классов, полностью исчезли с появлением нового синтаксиса.

Старый стиль инициализатора базового класса был сохранен на переходный период. Его .можно было использовать только при одиночном наследовании, поскольку в противном случае он неоднозначен.



Глава 13. Уточнения понятия класса

Говори, что хочешь сказать, просто и прямо.

Брайан Керниган

13.1 Введение

Поскольку концепция классов является центральной в С++, не прекращаются запросы о ее модификации и расширении. Почти все просьбы о модификации приходится отклонять ради сохранения существующего кода, а больигинство предложений о расширениях отвергались как излишние, непрактичные, не согласующиеся с другими частями языка или просто как слишком сложные для немедленной реализации . В этой главе представлено несколько уточнений, которые я счел достаточно важными, чтобы подробно рассмотреть и в большинстве случаев принять. Центральный вопрос - сделать концепцию классов достаточно гибкой, чтобы выразить все, что необходимо, оставаясь в рамках системы типов и не прибегая к приведениям типов и низкоуровневым конструкциям.

13.2. Абстрактные классы

Последнее средство, добавленное в версию 2.0 перед фиксацией, - абстрактные классы. Запоздалые модификации версий всегда непопулярны, а внесение в последний момент изменений в определение языка еще того хуже. Мне казалось, что несколько руководителей заподозрили меня в утрате представлений о реальности, когда я стал настаивать на включении этой возможности. К счастью, Барбара My поддержала меня в том, что абстрактные классы необходимы уже сегодня, а не через год-два.

Абстрактный класс предоставляет интерфейс. Прямая поддержка абстрактных классов:

□ помогает находить ошибки, возникающие из-за неправильного понимания роли классов как интерфейсов и их значения в представлении объектов;

□ способствует применению стиля проектирования, основанного на отделении спецификации интерфейсов от их реализации.

13.2.1. Абстрактные классы и обработка ошибок

с помощью абстрактных классов можно устранить некоторые источники ошибок [Stroustrup, 1989b]:



Одно из целей статического контроля типов - обноружить ошибки и противоречия еще до запуска прогроммы. Замечено, что большой класс поддающихся обнаружению ошибок пропускается системой контроля типов С++. Мало того, чтобы выявить такую ошибку, программисты вынуждены писать дополнительный код и генерировать более объемные программы.

Рассмотрим классический пример классе shape (геометрическоя фигура). Сначала мы объявляем класс shape, который представляет общее понятие фигуры. В нем должны быть две виртуальных функции; rotate () и draw(). Естественно, никаких объектов класса shape нет, есть только конкретные геометрические фигуры. К сожалению, в С++ нельзя выразить эту простую концепцию непрямую.

Правило С++ говорят, что виртуальные функции, такие как rotate () и draw {), должны быть определены в том классе, в котором они впервые объявлены. Причине требования - нужно скомпоновать С++-программу, пользуясь традиционными редакторами связей. Кроме того, необходимо горонтировать, что не будет вызываться неопределенная виртуальная функция. Поэтому прогроммисту предстоит написать примерно такой код:

class shape {

point center;

color col;

. . . public:

point where 0 { return center; }

void move(point p) { center=p; drawO; }

virtual void rotate(int)

{ error ( нельзя повернуть ); abortO; } virtual void drawO

{ error ( нельзя нарисовать ); abortO; } . . .

Если при этом пользователь забудет определить функцию draw () в классе, производном от shape (безобидная ошибка), или создаст просто фигуру и попытается ей воспользоваться (глупоя ошибка), то произойдет серьезный сбой во время выполнения. А если программист и не допустит таких ошибок, то память компьютера засоряется ненужными тоблицоми виртуальных функций для классов типа shape и невызываемыми функциями типа draw () и rotate (). Свя-зонные с этим затраты могут оказаться заметными.

Решение - доть пользователю возможность сказать, что у некоторой виртуальной функции нет определения, то есть она является исключительно виртуальной . Это делается с помощью инициализатора =0.

class shape {

point center;

color col;

. . . public:

point where0 { return center; }

void move(point p) { center=p; drawO; }

virtual void rotate(int) =0; чисто виртуальная функция virtual void drawO = 0; чисто виртуальная функция

. . .



1 ... 87 88 89 [ 90 ] 91 92 93 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика