(2) Les fonctions membres sont réécrites par le compilateur. Considérez class A
comme suit.
class A {
int i;
public:
A() : i (0) { }
void f (int a, char *b) { i = a; }
}
Alors ce que le compilateur fait de A::f
ressemble à quelque chose comme ça (pseudo-code):
void A::f (A * const this, int a, char *b) { this->i = a; }
Considérons maintenant un appel à A::f
.
A a;
a.f (25, "");
le compilateur génère un code similaire à ce (pseudo-code):
A a;
A::f (&a, 25, "");
En d'autres termes, le compilateur fonctionne le pointeur this
caché dans chaque fonction membre non statique et chaque appel reçoit une référence à l'instance à laquelle il a été appelé. Ceci, en particulier, signifie que vous pouvez appeler des fonctions membres non statiques sur des pointeurs NULL
.
A *a = NULL;
a->f (25, "");
L'accident ne se produit que lorsque vous faites référence en fait des variables membres de classe non statique. Le rapport d'accident qui en résulte illustre également la réponse à la question (1). Dans la plupart des cas, vous ne plantez pas sur l'adresse 0
, mais un décalage de cela. Ce décalage correspond au décalage que la variable accédée a dans la disposition de la mémoire choisie par le compilateur pour class A
(dans ce cas, de nombreux compilateurs vont effectivement le compenser avec 0x0
et class A
ne seront pas distingués en mémoire de struct A { int i; };
).Fondamentalement, les pointeurs vers les classes sont des pointeurs vers la structure C équivalente. Les fonctions membres sont implémentées en tant que fonctions libres en prenant comme référence une instance comme premier argument. Toutes les vérifications d'accès à l'égard des membres publics, protégés et privés sont faites au préalable par le compilateur, l'assemblée générée n'a aucune idée de l'un de ces concepts. En fait, les premières versions de C++ auraient été des ensembles de macros C intelligentes.
La disposition de la mémoire (généralement) change un bit lorsque vous avez des fonctions virtuelles.
Je pense que vous vouliez dire "comme ces choses ne sont pas traitées par l'assembleur, mais par les extrémités avant et arrière du compilateur". Et pour ajouter à cela, je pense que c'est juste le début et non la fin, dépend du compilateur et de son langage interne. –
@dwelch: réparé, ne devrait pas poster si tôt le matin: p – Necrolis