|
Программирование >> Разработка устойчивых систем
5. Включите в базовый класс из предыдущего упражнения функцию preparelnstrument(), которая бы вызывала соответствующую функцию (например, clearSpitValve() для духовых инструментов). Обратите внимание: функция preparelnstrumentO уместно смотрится в базовом классе и позволяет обойтись без RTTI, как это сделано в предыдущем примере. 6. Создайте вектор с указателями на 10 случайно выбранных объектов Shape (например, Square и Circle). Функция draw() переопределяется в каждом классе и печатает размеры выводимого объекта (например, радиус окружности, там где это уместно). Напищите функцию main(), которая сначала рисует все объекты Square контейнера, отсортированные по длине периметра, а затем - все объекты Circle, отсортированные по радиусу. 7. Создайте большой вектор с указателями на случайные объекты Shape. Включите в Shape невиртуальную функцию draw(), которая бы средствами RTTI определяла динамический тип каждого объекта и исполняла соответствующий код вывода объекта в команде выбора. Затем перепишите иерархию как положено , с использованием виртуальных функций. Сравните объем кода и время выполнения обоих решений. 8. Создайте иерархию классов Pet, включающую производные классы Dog, Cat и Horse. Также создайте иерархию Food с классами Beef, Fish и Oats. Класс Dog содержит функцию eat(), получающую параметр Beef; аналогично, функция Cat::eat() получает объект Fish, а объекты Oats передаются Horse::eat(). Создайте вектор указателей на случайные объекты Pet, переберите его элементы и вызовите для каждого функцию eat() с передачей правильного типа объекта Food. 9. Создайте глобальную функцию drawQuad(), получающую ссылку на объект Shape. Если параметр Shape представляет прямоугольную фигуру (то есть относится к фактическому типу Square или Rectangle), эта функция вызывает для него функцию draw(), а если нет - выводит предупреждающее сообщение. Переберите вектор указателей на объекты Shape и вызовите drawQuadO для каждого объекта. В векторе должны находиться указатели на Square, Rectangle, Circle и Triangle. 10. Отсортируйте вектор случайных объектов Shape по имени класса. Используйте функцию type info::before() в качестве функции сравнения при сортировке. Множественное наследование Основной принцип множественного наследования формулируется достаточно просто: новый тип создается наследованием от нескольких базовых классов. Синтаксис выглядит именно так, как следует ожидать, и если иерархии классов достаточно просты, то и множественное наследование не порождает особых проблем. Тем не менее, при множественном наследовании могут встречаться различные неоднозначности и странные ситуации, которые будут рассматриваться в этой главе. Но для начала стоит поближе познакомиться с этим предметом. История До появления C++ самым успешным объектно-ориентированным языком был Smalltalk. Он изначально проектировался как объектно-ориентированный язык. Его нередко называют чистым языком, тогда как C++ из-за поддержки разных парадигм программирования, помимо собственно объектно-ориентированной парадигмы, характеризуется как гибридный. Разработчики Smalltalk решили, что все классы должны быть производными от общего базового класса Object (так называемая объектно-базированная иерархия). В Smalltalk невозможно создать новый класс, который бы не являлся производным от одного из существующих классов; следовательно, прежде чем браться за создание новых классов, программисту приходилось изучать библиотеку классов. Таким образом, иерархия классов Smalltalk представляет собой единое монолитное дерево. Классы Smalltalk обычно обладают рядом общих характеристик, и уж по крайней мере обладают некоторыми общими характеристиками (унаследованными от класса Object), поэтому потребность в наследовании от нескольких базовых классов возникает нечасто. С другой стороны, C++ позволяет создать сколько угодно Также используется в Java и других объектно-ориентированных языках. Object Bitlmage
Это весьма убедительный аргумент в пользу множественного наследования. На базе этой модели были построены многие библиотеки классов. Тем не менее, как было показано в главе 5, поддержка шаблонов изменила подход к построению контейнеров, поэтому этот аргумент отчасти утратил свою значимость. Применение множественного наследования также может быть оправданно, если оно делает общую архитектуру системы более гибкой или практичной (хотя бы внешне). Примером служит исходная архитектура библиотеки потоков ввода-вывода (которая, кстати, сохранилась и в современной шаблонной архитектуре, описанной в главе 4): Приведенные номера соответствуют внутренней нумерации версий, принятой в AT&T. независимых иерархий наследования. Следовательно, ради логической полноты язык должен допускать объединение классов из разных иерархий - так возникает идея множественного наследовании. Впрочем, в течение долгого времени было непонятно, действительно ли нельзя обойтись без множественного наследования. Его необходимость в С++ вызывала (и продолжает вызывать) жаркие дискуссии. Поддержка множественного наследования была впервые реализована в 1989 году в AT&T cfront 2.0 и стала первым существенным изменением в языке с момента выхода версии 1.0. С того времени в стандарт С++ был включен ряд других возможностей (прежде всего шаблоны), которые изменили классический подход к программированию, и множественное наследование отошло на второй план. Сейчас многие рассматривают его как второстепенную языковую возможность, редко применяемую в повседневной работе. Один из самых веских доводов в пользу множественного наследования связан с контейнерами. Предположим, вы хотите создать контейнер, в котором можно хранить произвольные объекты. Первое очевидное решение - использовать тип void* для представления типов, хранящихся в контейнере. В Smalltalk эта задача решается просто: вы создаете контейнер для хранения типа Object, базового типа в иерархии Smalltalk. Поскольку все типы Smalltalk в конечном счете являются производными от Object, в контейнере с элементами Object можно хранить все, что угодно. Но вернемся к С++. Предположим, разработчик А создает объектно-базированную иерархию с полезным набором контейнеров. В эту иерархию входит и нужный вам контейнер Holder. Далее в иерархии классов разработчика В обнаруживается другой нужный класс, скажем, класс Bitlmage, предназначенный для хранения графики. Создать контейнер Holder с элементами Bitlmage можно только одним способом: объявить новый класс производным от Object, чтобы он мог храниться как в Holder, так и в Bitlmage:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |