Множественное наследование
У каждого из представленных дочерних классов CLine, CRect и CEllipse имеется один базовый класс CPos. Вместе с тем язык С++ предоставляет возможность создавать дочерние классы на основе нескольких базовых, что приводит к концепции множественного наследования. Реализуем концепцию множественного наследования, создав иерархию классов в соответствии с Рис. 21, добавив еще один абстрактный класс с именем CProp, который будет отвечать за свойства графических примитивов: толщину и цвет линии:
Теперь дочерние классы CLine, CRect и CEllipse можно образовывать от двух базовых CPos и CProp, которые являются не связанными друг с другом. Для того чтобы построить класс на основе двух базовых они указываются друг за другом через запятую.
Конструктор CLine(int, int, int, int, int, int) класса CLine вызывает конструкторы двух базовых классов, которые перечислены через запятую с указанием в них конкретных переменных. Работа с функциями класса CLine через его представитель имеет следующий вид:
Дружественные классы и функции Классы и функции, объявленные как дружественные к базовым классам, получают доступ к свойствам и методам, объявленным не только как public и protected, но и как private.
Для объявления дружественного класса используется ключевое слово friend, за которым следует имя класса. Следующий пример демонстрирует объявление дружественного класса CRect классам CPos и CProp:
В первой строке листинга использован прототип описания класса CRect, который сообщает компилятору о том, что такой класс есть, но его описание будет дано ниже. В результате использования спецификатора friend частные элементы X1, Y1, X2, Y2, width и color классов CPos и CProp оказываются доступными только одному производному классу CRect и никакому другому, что обеспечивает их лучшую защиту по сравнению с уровнем доступа protected. Дружественными можно объявлять не только классы, но и отдельные функции классов. Рассмотрим пример, в котором для класса CEllipse свойства X1, Y1, X2, Y2, width и color будут доступны только дружественной функции Draw().
Благодаря тому, что функция Draw() является дружественной классу CPos, она может получать доступ к частным элементам этого класса через переданный ей указатель на объект класса CPos. Виртуальные функции Функция-член класса может содержать спецификатор virtual. Такая функция называется виртуальной. Если некоторый класс содержит виртуальную функцию, а производный от него класс содержит функцию с тем же именем и типами формальных параметров, то обращение к этой функции для объекта производного класса вызывает функцию, определённую именно в производном классе. Функция, определённая в производном классе, вызывается даже при доступе через указатель или ссылку на базовый класс. В таком случае говорят, что функция производного класса подменяет функцию базового класса. Если типы функций различны, то функции считаются разными, и механизм виртуальности не включается. Ошибкой является различие между функциями только в типе возвращаемого значения.
В качестве базового класса создан абстрактный класс Animal. Он имеет единственное свойство Title, описывающий кличку животного. В нем есть единственная чистая виртуальная функция speak(), которая описывает, какие звуки издает животное. Из этого класса выведены все остальные. Кроме одного. Класс Lion порожден от класса Cat (ведь львы это тоже кошки). Это сделано для демонстрации тонкостей применения виртуальных функций. Во всех производных классах описана собственная замещающая виртуальная функция speak(), которая печатает на экран, какие же звуки издает конкретное животное. Объявим в основном теле программы массив animals[4] указателей типа Animal*. И сразу же создадим динамические объекты классов, которыми заполним массив указателей. А в цикле for() по указателю будем просто вызывать виртуальную функцию speak() для экземпляров класса.
В описании класса Lion содержится сразу три виртуальной функции speak(), правда две из них имеют типичные ошибки и закомментированы. Рассмотрим их. Во второй функции speak() класса Lion производится попытка соорудить виртуальную замещающую функцию с другим типом возвращаемого значения (функция возвращает тип int вместо типа void, который был у функции speak() в базовом классе). Компилятор выдаст сообщение об ошибке:
Третья (ошибочная) функции speak() класса Lion не определяется компилятором как ошибка, на сей раз он выдаст предупреждение (и программа будет работать!). Это тот самый случай, когда объявляется замещающая виртуальная функция с тем же самым типом возвращаемого значения, но с другим набором параметров. И, раз в данном классе нет идентично определенной виртуальной функции, то по указателю вызывается виртуальная функция speak() из базового класса Cat.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|