Tables virtuelles et pointeurs virtuels pour plusieurs héritages virtuels et transtypage de type
Je suis un peu confus au sujet de vptr et la représentation des objets dans la mémoire, et j'espère que vous pourrez m'aider à comprendre la question mieux.
- Envisager
B
hérite deA
et à la fois de définir des fonctions virtuellesf()
. De ce que j'ai appris de la représentation d'un objet de la classe B dans la mémoire ressemble à ceci:[ vptr | A | B ]
et levtbl
quevptr
points d'contientB::f()
. J'ai aussi compris que le casting de l'objet à partir deB
àA
ne fait rien, sauf en ignorant laB
partie à la fin de l'objet. Est-il vrai? N'a pas ce comportement est mauvais? Nous voulons que l'objet de typeA
pour exécuterA::f()
méthode et pasB::f()
. - Il y a un certain nombre de
vtables
dans le système comme le nombre de classes? - Comment un
vtable
de classe qui hérite de deux ou plusieurs classes? Comment sera l'objet de la C d'être représenté dans la mémoire? - Même que la question 3, mais avec l'héritage virtuel.
source d'informationauteur Artium
Vous devez vous connecter pour publier un commentaire.
Suivantes est vraie pour GCC, mais peut-être aussi vrai pour le compilateur que vous utilisez. Tous ces la mise en œuvre est-à charge, et n'est pas régi par la norme C++. Cependant, GCC écrire son propre binaire standard de document, Itanium ABI.
J'ai essayé d'expliquer les concepts de base de la façon dont des tables virtuelles sont énoncées dans la plus simple des mots comme une partie de mon l'article sur les performances de la fonction en C++qui pourront vous être utiles. Voici les réponses à vos questions:
Un plus bonne façon de dépeindre la représentation interne de l'objet est:
B
contient sa classe de baseA
il ajoute juste un couple de ses propres membres après sa fin.Casting de
B*
àA*
en effet, ne fait rien, il retourne le pointeur de même, etvptr
reste le même. Mais, en un mot, fonctions virtuelles ne sont pas toujours appelé par vtable. Parfois, ils sont appelés comme les autres fonctions.Voici des explications plus détaillées. Vous devez distinguer deux façons d'appeler la fonction membre:
Le truc, c'est qu'on sait que au moment de la compilation la façon dont la fonction sera appelée: via vtable ou tout simplement être un appel habituel. Et le truc, c'est que le type d'un casting expression est connue au moment de la compilationet, par conséquent, le compilateur choisit le droit de la fonction au moment de la compilation.
Il n'a même pas regarder à l'intérieur de vtable dans ce cas!
En général, non. Une classe peut avoir plusieurs vtables si il hérite de plusieurs bases, chacune ayant ses propres vtable. Ensemble de tables virtuelles les formes d'une table virtuelle de groupe" (voir pt. 3).
Classe a également besoin d'un jeu de construction vtables, correctement distpatch fonctions virtuelles lors de la construction de bases d'un objet complexe. Vous pouvez lire plus loin dans la norme j'ai relié.
Voici un exemple. Supposons
C
hérite deA
etB
chaque classe définissantvirtual void func()
ainsi quea
,b
ouc
fonction virtuelle pertinents à son nom.La
C
aura une vtable groupe de deux vtables. Il va partager une vtable avecA
(la vtable où les fonctions propres de la classe actuelle go est appelé "primaire"), et une vtable pourB
sera ajouté:La représentation de l'objet dans la mémoire va chercher près de la même manière ses vtable ressemble. Il suffit d'ajouter une
vptr
avant chaque vtable dans un groupe, et vous aurez une estimation approximative de la façon dont les données sont disposées à l'intérieur de l'objet. Vous pouvez lire à ce sujet dans le section pertinente de la GCC binaire standard.Virtuel bases (certains d'entre eux) sont disposés à l'extrémité de la vtable de groupe. Ceci est fait parce que chaque classe doit avoir qu'une seule base virtuelle, et si ils ont été mêlés avec "l'habitude" vtables, puis compilateur ne pouvais pas re-utiliser des parties de construit vtables à faire de ceux des classes dérivées. Cela conduirait à l'informatique inutiles décalages et permettrait de diminuer les performances.
En raison d'un tel placement, virtuel bases aussi introduire dans leur vtables éléments supplémentaires:
vcall
offset (pour obtenir l'adresse d'une finale overrider lors du passage du pointeur sur une base virtuelle à l'intérieur d'un objet pour le début de la classe qui remplace la fonction virtuelle) pour chaque fonction virtuelle qui y sont définies. Aussi chaque de base virtuelle ajoutevbase
compensations, qui sont insérées dans la vtable de la classe dérivée; ils permettent de trouver l'endroit où les données de la base virtuelle de commencer (il ne peut pas être précompilés depuis l'adresse réelle dépend de la hiérarchie: virtual bases sont à la fin de l'objet, et le passage de début varie en fonction du nombre de non-classes virtuelles, l'actuelle classe hérite.).Wouf, j'espère que je n'introduisent pas de beaucoup de complexité inutile. Dans tous les cas, vous pouvez vous référer à la norme d'origine, ou de tout document de votre propre compilateur.
Je vous recommande de lire L'Héritage Multiple Est Considéré Comme Utile , c'est un long article, mais il rend les choses plus claires sur le sujet comme il l'explique en détails comment l'héritage fonctionne en C++ (les chiffres des liens ne fonctionnent pas, mais ils sont disponibles au bas de la page).
Si l'objet B hérite de A, puis la représentation de la mémoire pour les B seront les suivantes:
Si vous avez B* b = new B(); (A)b->f() alors:
Chaque objet aura ses propres vtable (ne prenez pas cela pour acquis, comme je l'ai pour la recherche, il
Prendre un coup d'oeil à cette pour un exemple de vtable layour lorsque l'on traite de l'héritage multiple
Voir cette pour une discussion sur le diamant de l'héritage et de la vtable représentation