EDIT: Also ich bemerkte ich bin immer noch Stimmen später auf diesem Monat bekommen, auch wenn meine ursprüngliche Antwort ist schlecht und irreführend (Ich kann nicht einmal daran erinnern, was ich damals dachte, und es macht nicht viel Sinn!), also dachte ich, ich würde versuchen, die Situation zu klären, da die Leute immer noch durch die Suche hierher kommen müssen. nur
In der meisten normalen Situation, können Sie ziemlich viel denken an
struct A { int i; int foo() { return i; } };
A a; a.foo();
als
struct A { int i; };
int A_foo(A* this) { return this->i; };
A a; A_foo(&a);
(Start wie C
aussehen, nicht wahr?) Also würde man den Zeiger &A::foo
würde denken ist der gleiche wie ein normaler Funktionszeiger. Aber es gibt ein paar Komplikationen: Mehrfachvererbung und virtuelle Funktionen.
So vorstellen, die wir haben:
struct A {int a;};
struct B {int b;};
struct C : A, B {int c;};
Es könnte so ausgelegt werden:
Wie Sie sehen können, wenn Sie mit einem A*
auf das Objekt verweisen soll oder a C*
, zeigen Sie auf den Anfang, aber wenn Sie mit einer B*
darauf zeigen möchten, müssen Sie irgendwo in der Mitte zeigen.Also, wenn C
erbt Mitglied Funktion von B
und Sie darauf zeigen möchten, dann rufen Sie die Funktion auf eine C*
, muss es wissen, um die this
Zeiger zu mischen. Diese Information muss irgendwo gespeichert werden. Also wird es mit dem Funktionszeiger in Verbindung gebracht.
Jetzt für jede Klasse, die virtual
Funktionen hat, erstellt der Compiler eine Liste von ihnen als eine virtuelle Tabelle. Es fügt dann der Klasse einen zusätzlichen Zeiger auf diese Tabelle hinzu (vptr). Also für diese Klasse Struktur:
struct A
{
int a;
virtual void foo(){};
};
struct B : A
{
int b;
virtual void foo(){};
virtual void bar(){};
};
Der Compiler könnte am Ende es so machen:
So Mitglied Funktionszeiger auf eine virtuelle Funktion tatsächlich benötigt ein Index in der virtuellen Tabelle sein. So ein Mitgliedsfunktionszeiger benötigt tatsächlich 1) möglicherweise einen Funktionszeiger, 2) möglicherweise eine Anpassung des this
Zeigers und 3) möglicherweise einen Vtable-Index. Um konsistent zu sein, muss jeder Mitgliedsfunktionszeiger zu all diesen fähig sein. Das ist also 8
Bytes für den Zeiger, 4
Bytes für die Anpassung, 4
Bytes für den Index, für 16
Bytes insgesamt.
Ich glaube, das ist etwas, das tatsächlich viel zwischen Compiler variiert, und es gibt viele mögliche Optimierungen. Wahrscheinlich implementiert es keiner so, wie ich es beschrieben habe.
Für ein Los des Details, siehe this (blättern Sie zu "Implementierungen von Member Function Pointers").
Im Wesentlichen erfordert der Standard nicht, dass Datenzeiger, Funktionszeiger und Elementfunktionszeiger alle die gleiche Größe haben. Wenn Sie wissen wollen, warum sie auf Ihrer Plattform nicht die gleiche Größe haben, müssen Sie die Betreuer Ihres C++ - Compilers fragen. http://www.parashift.com/c++-faq/cant-cvt-memfnptr-to-vovotrp.html http://www.parashift.com/c++faq/cant-cvt-fnptr-to-vovotrp.html – Cubic
@KirilKirov kein Problem. Ich bin nicht immer sarkastisch :) –