05.09.2016 Views

Стефан Р. - С++ Для чайников

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

При использовании виртуальных функций следует не забывать о некоторых вещах.<br />

Во-первых, статические функции-члены не могут быть объявлены виртуальными.<br />

Поскольку статические функции-члены не вызываются с объектом, никакого объекта<br />

этапа выполнения не может быть, а значит, нет и его типа.<br />

Во-вторых, при указании имени класса в вызове функция будет компилироваться<br />

с использованием раннего связывания независимо от того, объявлена она виртуальной<br />

или нет.<br />

Например, приведенный ниже вызов обращается к Base::fn(], поскольку так<br />

указал программист, независимо от того, объявлена f n () виртуальной или нет.<br />

void test (Bases b)<br />

{<br />

b.base::fn f);<br />

//Этот вызов не использует позднего связывания<br />

}<br />

Кроме того, виртуальная функция не может быть встроенной. Чтобы подставить<br />

функцию на место ее вызова, компилятор должен знать ее на этапе компиляции. Таким<br />

образом, независимо от способа описания виртуальные функции-члены рассматриваются<br />

как не встроенные.<br />

И наконец, конструкторы не могут быть виртуальными, поскольку во время работы<br />

конструктора не существует завершенного объекта какого-либо определенного типа.<br />

В момент вызова конструктора память, выделенная для объекта, является просто<br />

аморфной массой. И только после окончания работы конструктора объект становится<br />

экземпляром класса в полном смысле этого слова.<br />

В отличие от конструктора, деструктор может быть объявлен виртуальным. Более<br />

того, если он не объявлен виртуальным, вы рискуете столкнуться с неправильной ликвидацией<br />

объекта, как, например, в следующей ситуации:<br />

class Base<br />

f<br />

public:<br />

-Base () ;<br />

);<br />

class Subclass : public Base<br />

(<br />

public:<br />

-Subclass();<br />

void finishWithObject{Base* pHeapObject)<br />

{<br />

delete pHeapObject; //Здесь вызывается -Basef)<br />

//независимо от типа<br />

//указателя pHeapObject<br />

)<br />

Если указатель, передаваемый функции f inishWithObject (), на самом деле указывает<br />

на объект Subclass, деструктор Subclass все равно вызван не будет: поскольку<br />

он не был объявлен виртуальным, используется раннее связывание. Однако,<br />

если объявить деструктор виртуальным, проблема будет решена.<br />

А если вы не хотите объявлять деструктор виртуальным? Тому может быть только<br />

одна причина: виртуальные функции несколько увеличивают размер объекта. Когда<br />

программист определяет первую виртуальную функцию в классе, C++ прибавляет<br />

Глава 22. Знакомство с виртуальными функциями-членами: настоящие л

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!