Языки программирования - концепции и принципы

зации не возникает никаких проблем,


рис. 14.4). При реали­ зации не возникает никаких проблем, потому что мы принимаем, что все ука­затели представляются одинаково независимо от указуемого типа.



    Важно обратить внимание на то, что после присваивания указателя компи­лятор больше не имеет никакой информации относительно типа указуемого объекта. Таким образом, у него нет возможности привязать вызов

Base_Ptr- >virtual_proc();

к правильной подпрограмме, и следует выполнить динамическую диспетче­ризацию. Аналогичная ситуация возникает, когда используется ссылочный параметр, как было показано выше.

    Эта ситуация может внести путаницу, так как программисты обычно не де­лают различия между переменной и указуемым объектом. После следующих операторов:

inti1 = 1;

int i2 = 2;

int *p1 = &i1;                      // p1 ссылается на i1

int *p2 = &i2;                      // p2 ссылается на i2

p1 = p2;                                // p1 также ссылается на i2

i1 = i2;                                  // i1 имеет то же самое значение, что и i2

вы ожидаете, что i1 == i2 и *р1 ==*р2; это, конечно, правильно, пока типы в точности совпадают, но это неверно для присваивания производного класса базовому классу из-за усечения. При использовании наследования вы долж­ны помнить, что указуемый объект может иметь тип, отличный от типа указу­емого объекта в объявлении указателя.

    Есть одна западня в семантике динамического полиморфизма языка C++: если вы посмотрите внимательно, то заметите, что обсуждение касалось дис­петчеризации, относящейся к замещенной виртуальной подпрограмме. Но в классе могут также быть и обычные подпрограммы, которые замещаются:

Base_Ptr = Derived_Ptr;

Base_Ptr->virtual_proc();        // Диспетчеризуется по указанному типу

Base_Ptr->ordinary_proc();     // Статическое связывание с базовым типом!!

Существует различие в семантике между двумя вызовами: вызов виртуальной подпрограммы диспетчеризуется во время выполнения в соответствии с ти­пом указуемого объекта, в данном случае Derived_Class; вызов обычной под­программы связывается статически во время компиляции в соответствии с типом указателя, ъ данном случае Base_Class.

Содержание  Назад  Вперед