|
Программирование >> Полиморфизм без виртуальных функций в с++
Инициализаторы членов и базовых классов В первоначальном определении С++ не требовалось, да и не разрешалось именовать базовый класс в инициализаторе. Например, если есть класс 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; чисто виртуальная функция . . .
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |