Заранее оговорюсь о том, что конкретные значения размеров указателей могут варьироваться от компилятора к компилятору. Значения приведенные в данной статье верны для MS Visual Studio 2005, 2008. Однако основной интерес в том, что они не равны 4-м байтам. Сначала приведем основной код, который и будет рассматриваться в данной статье class Base { public: void f() { std::cout << "Base"; } };
Использовать методы этих классов можно следующим образом: создаем указатель на метод класса Base void(Base::* F) ();
присваиваем ему адрес метода класса Base F = &Base::f;
Для нас самым важным в этом отрывке было то, что размер указателя F после присвоения равен 4-м байтам. В общем, необязательно даже что-то присваивать этому указателю. Если убрать последнюю строчку и просто вызвать sizeof(F), то результат тоже будет 4. При добавлении еще одного класса class Base1 { public: int m_base1; void f() { std::cout << "Base1"; } };
и наследовании от него ABase class ABase : public Base, public Base1 ...
указатель F объявленный вот так void(ABase::* F) ();
станет равен 8-ми байтам. Структура указателя будет такой: -------------- |adress|index| -------------- 4 + 4 = 8 байт
где adress - адрес функции, index - смещение, необходимое для вычисления this для вызова соответствующей функции. И наконец, доведем нашу ситуацию до абсурда. Если ABase унаследовать виртуально от обоих родителей class ABase : virtual public Base, virtual public Base1 ...
то размер указателя F станет равным 12-ти байтам. Его структура станет такой ---------------------- |adress|index|vbIndex| ---------------------- 4 + 4 + 4 = 12 байт
где adress - адрес функции, index - смещение, необходимое для вычисления this для вызова соответствующей функции, vbIndex - смещение, необходимое, для узнавания местарасположения таблицы виртуальных базовых классов.
|