вызов виртуальных функций через указатели с использованием и без обращения к VM-таблице - PullRequest
5 голосов
/ 13 июля 2011

Я хочу взять адрес функции-члена класса c ++, сохранить его в указателе и позже вызвать виртуальную функцию.

Я знаю кое-что об этом, но сейчас не знаю, как получить адрес определенной реализации виртуальной функции, которая НЕ является реализацией самого потомственного класса (фактического класса объекта).

Вот пример кода:

    #include <iostream>

    using namespace std;

    class ca
    {
            public:
            virtual void vfunc() {cout << "a::vfunc ";}
            void mfunc() {cout << "a::mfunc ";}
    };

    class cb : public ca
    {
            public:
            virtual void vfunc() {cout << "b::vfunc ";}
    };

    extern "C" int main(int, char **)
    {
            void (ca:: *ptr_to_vfunc)() = &ca::vfunc;

            cout << sizeof(ptr_to_vfunc) << " ";

            cb b;

            (b.*ptr_to_vfunc)();

            ca a;

            (a.*ptr_to_vfunc)();

            void (ca:: *ptr_to_mfunc)() = &ca::mfunc;

            cout << sizeof(ptr_to_mfunc) << " ";
            (a.*ptr_to_mfunc)();
    }

Вывод:

12 b :: vfunc a :: vfunc 12 a :: mfunc

Я работаю с win32-средой, а размер указателей на функции-члены составляет 3 * 32-битные значения!Я не указывал объект, когда брал адрес функции-члена, и все же мой вызов вызывает реализацию vfunc () наиболее наследуемого класса.

1) Что здесь происходит?Почему 12 байтов вместо 4?2) Как я могу взять адрес ca :: vfunc () и вызвать его на b, как я обычно делал бы с b.ca::vfunc ().

1 Ответ

2 голосов
/ 13 июля 2011

Хорошо: он делает именно то, что должен.

Но чтобы ответить на ваши вопросы:

1) Что здесь происходит? Почему 12 байтов вместо 4?

Почему бы и нет.
Стандарт не устанавливает размер.
Я не уверен, почему вы ожидаете, что нормальный указатель будет 4.

Если вопрос «почему указатель на метод больше, чем обычный указатель?»

Поскольку реализации требуется дополнительное пространство для хранения информации о вызове.

2) Как я могу взять адрес ca :: vfunc () и вызвать его на b, как я обычно делал бы с b.ca::vfunc().

Вы не можете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...