Ответ 1
РЕДАКТИРОВАТЬ. Итак, я заметил, что я все еще получаю голоса в эти месяцы позже, хотя мой первоначальный ответ плох и обманчив (я даже не могу вспомнить, что я думал в то время, и это не имеет большого смысла!), поэтому я решил попробовать и прояснить ситуацию, так как люди все равно должны добраться сюда через поиск.
В самой нормальной ситуации вы можете в значительной степени подумать о
struct A { int i; int foo() { return i; } };
A a; a.foo();
а
struct A { int i; };
int A_foo( A* this ) { return this->i; };
A a; A_foo(&a);
(Начиная выглядеть как C
, правильно?) Итак, вы думаете, что указатель &A::foo
будет просто таким же, как обычный указатель на функцию. Но есть несколько осложнений: множественное наследование и виртуальные функции.
Итак, представьте, что у нас есть:
struct A {int a;};
struct B {int b;};
struct C : A, B {int c;};
Это может быть сделано следующим образом:
Как вы можете видеть, если вы хотите указать на объект с помощью A*
или C*
, вы указываете на начало, но если вы хотите указать на него с помощью B*
, вы должны указать где-то посередине. Поэтому, если C
наследует некоторую функцию-член из B
, и вы хотите указать на нее, затем вызовите функцию в C*
, ее необходимо знать, чтобы перетасовать указатель this
. Эта информация должна быть где-то сохранена. Таким образом, он включается с указателем функции.
Теперь для каждого класса, имеющего функции virtual
, компилятор создает список из них, называемый виртуальной таблицей. Затем он добавляет дополнительный указатель на эту таблицу в класс (vptr). Итак, для этой структуры класса:
struct A
{
int a;
virtual void foo(){};
};
struct B : A
{
int b;
virtual void foo(){};
virtual void bar(){};
};
Компилятор может сделать это следующим образом:
Таким образом, указатель функции-члена для виртуальной функции на самом деле должен быть индексом в виртуальной таблице.
Таким образом, указатель функции-члена действительно нуждается в 1) возможно, указателе функции, 2) возможно, настройке указателя this
и 3), возможно, индексе vtable. Чтобы быть последовательным, каждый элемент-указатель функции должен быть способен на все это. Так что 8
байтов для указателя, 4
байтов для настройки, 4
байтов для индекса, для 16
всего байтов.
Я считаю, что это очень многое зависит от компиляторов, и есть много возможных оптимизаций. Вероятно, никто не реализует его так, как я описал.
Подробные сведения см. в this (перейдите к "Реализации указателей функций членов" ).