О sizeof указателя функции члена класса

Скажем, что мы имеем класс A

class A;

и эти typedefs

typedef void (A::*a_func_ptr)(void);
typedef void (*func_ptr)(void);

Мой вопрос в том, почему sizeof (a_func_ptr) возвращает 16, а sizeof (func_ptr) возвращает 4 (как для любого указателя на системе x86)?

Например

int main(int argc, char *argv[])
{
  int a = sizeof(a_func_ptr);
  int b = sizeof(func_ptr);
}

Ответ 1

Мой вопрос в том, почему sizeof (a_func_ptr) возвращает 16, а sizeof (func_ptr) возвращает 4 (как для любого указателя на системе x86)?

Поскольку указатели на элементы выполняются по-разному. Они не указатели под капотом. Некоторые компиляторы, такие как MSVC, реализуют их как struct с несколькими членами в нем.

Прочитайте эту интересную статью:

Обратите внимание, что в некоторых компиляторах они могут иметь одинаковый размер. Нижняя линия: они зависят от компилятора.

Ответ 2

Учтите следующее:

#include <iostream>

class A {
public:
    virtual void foo(){ std::cout << "A::foo" << std::endl; }
    void bar(){ std::cout << "A::bar" << std::endl; }
};

class B : public A {
public:
     void foo(){  std::cout << "B::foo" << std::endl; }
     void bar(){ std::cout << "B::bar" << std::endl; }
};

typedef void (A::*a_func_ptr)(void);

int main() {
   a_func_ptr f = &A::foo;
   a_func_ptr g = &A::bar;
   B b;
   A a;
   (b.*f)();
   (b.*g)();
   (a.*f)();
   (a.*g)();
}

Выход:

B::foo
A::bar
A::foo
A::bar

Оба указателя члена имеют один и тот же тип, но оба правильно перенаправляют вызов в каждом случае.

Каким-то образом сгенерированная программа должна знать, когда указатель на метод на самом деле является простым или виртуальным методом. Таким образом, представление указателя метода во время выполнения должно включать больше информации для обработки второго случая.

Примечание: размер, кажется, зависит от реализации (я получаю 8 на моей системе).

Ответ 3

Функция указателя на член класса не содержит "точный адрес", как это делает обычный указатель. Он хранит больше информации, чем обычный указатель функции.

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

Ответ 4

Хотя указатели на функции в C и С++ могут быть реализованы как простые адресов, так что обычно sizeof (Fx) == sizeof (void *), член указатели на С++ часто реализуются как "указатели жира", обычно два или в три раза больше простого указателя функции, чтобы с виртуальным наследованием.

Источник: Wikipedia

Этот ответ SO содержит дополнительную информацию.