item = bulk; //
При создании объекта item
выполняется конструктор копий класса Quote
. Этот конструктор знает только о переменных-членах bookNo
и price
. Он копирует эти члены из части Quote
объекта bulk
и игнорирует члены, являющиеся частью Bulk_quote
объекта bulk
. Аналогично при присвоении объекта bulk
объекту item
ему присваивается только часть Quote
объекта bulk
.
Поскольку часть Bulk_quote
игнорируется, говорят, что она была
При инициализации объекта базового типа (или присвоении) объектом производного типа копируется, перемещается или присваивается только часть базового класса производного объекта. Производная часть объекта игнорируется.
Есть три правила преобразования связанных наследованием классов, о которых следует помнить.
• Преобразование из производного класса в базовый применимо только к указателю или ссылке.
• Нет неявного преобразования из типа базового класса в тип производного.
• При преобразовании производного в базовый член класса может быть недоступен из за спецификатора управления доступом. Доступность рассматривается в разделе 15.5.
Хотя автоматическое преобразование применимо только к указателям и ссылкам, большинство классов в иерархии наследования (явно или неявно) определяют функции-члены управления копированием (см. главу 13). В результате зачастую вполне можно копировать, перемещать и присваивать объекты производного типа объектам базового. Однако копирование, перемещение или присвоение объекта производного типа объекту базового копирует, перемещает или присваивает
Упражнение 15.8. Определите статический и динамический типы.
Упражнение 15.9. Когда может возникнуть отличие статического типа выражения от его динамического типа? Приведите три примера, в которых статический и динамический типы отличаются.
Упражнение 15.10. Возвращаясь к обсуждению в разделе 8.1, объясните, как работает программа из раздела 8.2.1, где функции read()
класса Sales_data
передавался объект ifstream
.
Как уже упоминалось, в языке С++ динамическое связывание происходит при вызове виртуальной функции-члена через ссылку или указатель на тип базового класса (см. раздел 15.1). Поскольку до времени выполнения неизвестно, какая версия функции вызывается, виртуальные функции следует определять
Когда виртуальная функция вызывается через ссылку или указатель, компилятор создает код
В качестве примера рассмотрим функцию print_total()
из раздела 15.1. Она вызывает функцию net_price()
своего параметра item
типа Quote&
. Поскольку параметр item
— это ссылка и функция net_price()
является виртуальной, какая именно из ее версий будет вызвана во время выполнения, зависит от фактического (динамического) типа аргумента, связанного с параметром item
:
Quote base("0-201-82470-1", 50);
print_total(cout, base, 10); //
Bulk_quote derived("0-201-82470-1", 50, 5, .19);