Упражнение 15.18. С учетом классов Base и производных от него, и типов объектов, приведенных в комментариях, укажите, какие из следующих присвоений допустимы. Объясните, почему некорректны недопустимые.
Base *p = &d1 //
p = &d2 //
p = &d3 //
p = &dd1 //
p = &dd2 //
p = &dd3 //
Упражнение 15.19. Предположим, у каждого из классов: Base и производных от него, есть функция-член в формате
void memfcn(Base &b) { b = *this; }
Укажите, была ли эта функция допустима для каждого класса.
Упражнение 15.20. Напишите код проверки ответов на предыдущие два упражнения.
Упражнение 15.21. Выберите одну из следующих общих абстракций, содержащих семейство типов (или любую собственную). Организуйте типы в иерархию наследования.
(a) Форматы графических файлов (например: gif, tiff, jpeg, bmp)
(b) Геометрические примитивы (например: box, circle, sphere, cone)
(c) Типы языка С++ (например: class, function, member function)
Упражнение 15.22. Укажите имена некоторых из наиболее вероятных виртуальных функций, а также открытых и защищенных членов для класса, выбранного в предыдущем упражнении.
Каждый класс определяет собственную
Тот факт, что область видимости производного класса вложена в область видимости его базовых классов, может быть удивителен. В конце концов, базовые и производные классы определяются в разных частях текста программы. Но именно это иерархическое вложение областей видимости класса позволяет членам производного класса использовать члены его базового класса, как будто они являются частью производного класса. Рассмотрим пример:
Bulk_quote bulk;
cout << bulk.isbn();
В этом коде поиск определения имени isbn()
осуществляется следующим образом.
• Поскольку вызывается функция isbn()
объекта типа Bulk_quote
, поиск начинается в классе Bulk_quote
. В этом классе имя isbn()
не найдено.
• Поскольку класс Bulk_quote
происходит от класса Disc_quote
, в нем и продолжается поиск. Имя все еще не найдено.
• Поскольку класс Disc_quote
происходит от класса Quote
, поиск продолжается в нем. В этом классе находится определение имени isbn()
; таким образом, вызов isbn()
распознается как вызов функции isbn()
класса Quote
.
Статический тип (см. раздел 15.2.3) объекта, ссылки или указателя определяет, какие члены этого объекта будут видимы. Даже когда статический и динамический типы отличаются (это бывает в случае, когда используется ссылка или указатель на базовый класс), именно статический тип определяет применимые члены. Например, в класс Disc_quote
можно было бы добавить функцию-член, которая возвращает пару (тип pair
) (см. раздел 11.2.3), содержащую минимальное (или максимальное) количество и цену со скидкой.
class Disc_quote : public Quote {
public:
std::pair
{ return {quantity, discount}; }
//
};
Функцию discount_policy()
можно использовать только через объект, указатель, или ссылку на тип Disc_quote
, или класс, производный от него:
Bulk_quote bulk;
Bulk_quote *bulkP = &bulk //
Quote *itemP = &bulk //
bulkP->discount_policy(); //
itemP->discount_policy(); //