Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Статический вызов виртуальной функции



Вызывая виртуальную функцию с помощью оператора разрешения области видимости класса, мы отменяем механизм виртуализации и разрешаем вызов статически, на этапе компиляции. Предположим, что мы определили виртуальную функцию isA() в базовом и каждом из производных классов иерархии Query:

Query *pquery = new NameQuery( " dumbo" );

 

// isA() вызывается динамически с помощью механизма виртуализации

// реально будет вызвана NameQuery:: isA()

pquery-> isA();

 

// isA вызывается статически во время компиляции

// реально будет вызвана Query:: isA

pquery-> Query:: isA();

Тогда явный вызов Query:: isA() разрешается на этапе компиляции в пользу реализации isA() в базовом классе Query, хотя pquery адресует объект NameQuery.

Зачем нужно отменять механизм виртуализации? Как правило, ради эффективности. В теле виртуальной функции производного класса часто необходимо вызвать реализацию из базового, чтобы завершить операцию, расщепленную между базовым и производным классами. К примеру, вполне вероятно, что виртуальная функция display() из Camera выводит некоторую информацию, общую для всех камер, а реализация display() в классе PerspectiveCamera сообщает информацию, специфичную только для перспективных камер. Вместо того чтобы дублировать в ней действия, общие для всех камер, можно вызвать реализацию из класса Camera. Мы точно знаем, какая именно реализация нам нужна, поэтому нет нужды прибегать к механизму виртуализации. Более того, реализация в Camera объявлена встроенной, так что разрешение во время компиляции приводит к подстановке по месту вызова.

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

Реализации функции print() в классах AndQuery и OrQuery совпадают во всем, кроме литеральной строки, представляющей название оператора. Реализуем только одну функцию, которую можно вызывать из данных классов. Для этого мы снова определим абстрактный базовый BinaryQuery (его наследники – AndQuery и OrQuery). В нем определены два операнда и еще один член типа string для хранения значения оператора. Поскольку это абстрактный класс, объявим print() чисто виртуальной функцией:

class BinaryQuery: public Query {

public:

BinaryQuery( Query *lop, Query *rop, string oper )

        : _lop(lop), _rop(rop), _oper(oper) {}

 

~BinaryQuery() { delete _lop; delete _rop; }

ostream & print( ostream& =cout, ) const = 0;

 

protected:

Query *_lop;

Query *_rop;

string _oper;

};

Вот как реализована в BinaryQuery функция print(), которая будет вызываться из производных классов AndQuery и OrQuery:

inline ostream&

BinaryQuery::

print( ostream & os ) const

{

if ( _lparen )

    print_lparen( _lparen, os );

 

_lop-> print( os );

os < < ' ' < < _oper < < ' ';

_rop-> print( os );

 

if ( _rparen )

    print_rparen( _rparen, os );

 

return os;

}

Похоже, мы попали в парадоксальную ситуацию. С одной стороны, необходимо объявить этот экземпляр print() как чисто виртуальную функцию, чтобы компилятор воспринимал BinaryQuery как абстрактный базовый класс. Тогда в приложении определить независимые объекты BinaryQuery будет невозможно.

С другой стороны, нужно определить в классе BinaryQuery виртуальную функцию print() и уметь вызывать ее через объекты AndQuery и OrQuery.

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

inline ostream&

AndQuery::

print( ostream & os ) const

{

// правильно: подавить механизм виртуализации

// вызвать BinaryQuery:: print статически

BinaryQuery:: print( os );

}


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 260; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.009 с.)
Главная | Случайная страница | Обратная связь