2009-09-05 7 views
10

Mise à jour: Remplacement de l'exemple de destructeur par un exemple d'appel de méthode direct.C++ Héritage/questions VTable

Salut,

Si j'ai le code suivant:

class a 
{ 
public: 
    virtual void func0(); // a has a VTable now 
    void func1(); 
}; 
class b : public a 
{ 
public: 
    void func0() { a::func0(); } 
    void func2(); 
}; 
  1. est-il un VTable en B? B n'a pas de fonctions virtuelles mais appelle a: func0() de b :: func0()
  2. Est-ce que func1 réside dans une VTable? Ce n'est pas virtuel.
  3. Est-ce que func2 réside dans une VTable?
  4. Les réponses à ce qui précède seront-elles différentes s'il n'y a pas eu d'appel de a :: func0() dans b :: func0()?

Merci

+5

Je serais bien si vous dites dans ces questions quel compilateur vous utilisez. Les tables virtuelles sont spécifiques à l'implémentation, bien que des efforts soient déployés pour standardiser leur format. –

+2

'b :: func0' ** est ** virtuel –

Répondre

19

Si vous déclarez des fonctions virtuelles, vous devez également déclarer votre destructeur virtuel ;-).

  1. B dispose d'une table virtuelle, car il a une fonction virtuelle, à savoir func0(). Si vous déclarez une fonction (y compris un destructeur) virtuelle dans une classe de base, toutes ses classes dérivées auront aussi la fonction avec la même signature virtuelle. Et cela les amènera à avoir un vtable. De plus, B aurait la vtable même si vous n'y avez pas déclaré func0 explicitement.

  2. Les fonctions non virtuelles ne sont pas référencées via vtables.

  3. Voir 2.

  4. N ° de vtables de classes sont construites à partir des déclarations de classe. Les corps des fonctions de classe (sans parler des autres fonctions) ne sont pas pris en compte. Par conséquent, B a un vtable, car sa fonction func0() est virtuelle.

Il y a aussi un détail délicat, même si ce n'est pas l'essentiel de votre question. Vous avez déclaré votre fonction B::func0() comme en ligne. Dans le compilateur gcc, si une fonction virtuelle est déclarée en ligne, elle conserve son emplacement dans la table virtuelle, l'emplacement pointant vers une fonction spéciale émise pour celle en ligne (qui compte comme prenant son adresse, ce qui rend l'inline émise). Cela signifie que le fait que la fonction soit inline n'influence pas le nombre de slots dans vtable et sa nécessité pour une classe.

+0

Mis à jour. Aussi, si fondamentalement, si une fonction est déclarée virtuelle dans * any * base class dans la hiérarchie d'héritage, alors cette fonction est virtuelle même si la classe de base directe (1 niveau ci-dessus) ne la marque pas comme virtuelle? – jameszhao00

+0

Réponse remarquable. Devrait être l'accepté. +1 de moi. –

+0

@ jameszhao00: a également mis à jour la réponse. Vous l'avez compris: si une classe de base indirecte (c'est-à-dire un parent d'un parent d'un parent ... de la classe courante) déclare la fonction virtuelle, elle est également virtuelle dans la classe courante. Notez que les fonctions surchargées (void f (int) comparé à void f (double)) sont traitées comme des fonctions différentes. –

5
  1. Oui, parce que sa classe de base a un; son destructeur est également virtuel (même si vous ne l'avez pas déclaré virtuel) car le destructeur de la classe de base est virtuel.

  2. Pas

  3. No.

  4. Non. En fait, je ne pense pas que le code actuel est légal: le compilateur invoquera A destructor après invoque la B destructor même si vous n » t appelle explicitement ~ A à partir de ~ B; donc je ne pense pas que vous devriez appeler ~ A de ~ B même si le compilateur vous le permet.

+0

Désolé. Je n'aurais pas dû utiliser les destructeurs comme exemple. Actualisé. – jameszhao00

3

En se référant à l'exemple mis à jour:

  1. Oui, b a une vtable. Notez que b :: func0() est virtuel (redéfinit a :: func0()), même si vous ne l'étiez pas explicitement comme virtuel. Bizarre C++ "échappatoire", je suppose.
  2. Non. Les fonctions non-virtuelles ne résident pas dans la vtable.
  3. Voir 2.
  4. Non. Vous avez remplacé a: func0(); cela n'a pas d'importance si vous appelez a: func0() ou non.

Quelques notes supplémentaires (dépend du compilateur, mais ceux-ci sont des généralisations assez communes):

  • Chaque instance de b aura un pointeur vers un vtable, parce que vous êtes dérivée d'une classe qui a des fonctions virtuelles. Ceci est le cas même si vous n'avez pas défini b :: func0()
  • Dans cette situation, le compilateur peut avoir des cas de b points à un vtable statique de, ou il pourrait créer un vtable statique pour b et le remplir avec des pointeurs sur des pointeurs aux membres de un .
  • Mais il est encore nécessaire , de sorte que vous pouvez bien accéder à une instance de b via un pointeur vers un .
1
  • Si la fonction de la classe de base est virtuel alors si vous remplacez cette fonction dans la classe dérivée, il est même implicitement virtuel si vous ne spécifiez pas explicitement. Si la classe a une fonction virtuelle, alors elle a une table v.
  • Seules les fonctions virtuelles présentes dans vtable, function1 ne résidera pas dans vtable
  • fonction2 ne résidera pas dans vtable même raison ci-dessus
  • Création de vtable ne dépend pas du fait que vous appelez cette fonction de la classe de base ou d'ailleurs . L'appel de fonction ne décide pas de la création de vtable.