Бьерн Страуструп.
Язык программирования С++
156
employee
e("J.Brown",1234);
manager
m("J.Smith",2,1234);
employee::print_list();
}
напечатает
J.Smith 1234
level 2
J.Brown 1234
Обратите внимание, что функция печати будет работать даже в том случае, если функция
employee_list() была написана и оттранслирована еще до того, как был задуман конкретный
производный класс manager! Очевидно, что для правильной работы виртуальной
функции нужно в
каждом объекте класса employee хранить некоторую служебную информацию о типе. Как правило,
реализации в качестве такой информации используют просто указатель. Этот указатель хранится
только для объектов класса с виртуальными функциями, но не для объектов всех классов, и даже для
не для всех объектов производных классов. Дополнительная память отводится только для классов, в
которых описаны виртуальные функции. Заметим, что при использовании поля типа, для него все равно
нужна дополнительная память.
Если в вызове
функции явно указана операция разрешения области видимости ::, например, в вызове
manager::print(), то механизм вызова виртуальной функции не действует. Иначе подобный вызов привел
бы к бесконечной рекурсии. Уточнение имени
функции дает еще один положительный эффект: если
виртуальная функция является подстановкой (в этом нет ничего необычного), то в вызове с операцией
:: происходит подстановка тела функции. Это эффективный способ вызова, который можно применять в
важных случаях, когда одна виртуальная
функция обращается к другой с одним и тем же объектом.
Пример такого случая - вызов функции manager::print(). Поскольку тип объекта явно задается в самом
вызове manager::print(), нет нужды определять его в динамике для
функции employee::print(), которая и
будет вызываться.
Достарыңызбен бөлісу: