2010-06-23 4 views
-2

J'ai besoin de quelques réponses aux questions de base. Je suis perdu à nouveau. :(Fonction virtuelle et classes

q1 - Cette déclaration est valide:
Whenever we define the function to be pure virtual function, this means that function has no body.

q2 - Et quel est le concept de liaison dynamique, je veux dire si le compilateur optimise le code à l'aide VTables et VPTRs alors comment est-il d'exécution? ? polymorphisme

q3 - Quels sont vTables eT VPTRs et comment leurs tailles changent

q4 - S'il vous plaît voir ce code:

class base 
{ 
    public: 
     virtual void display() 
     { 
      cout<<"Displaying from base"; 
     } 
}; 

class derived:public base 
{ 
    public: 
     void display(){cout<<"\nDisplaying from derived";} 
}; 

int main() 
{ 
    base b,*bptr; 
    derived d; 
    bptr=&b; 
    bptr->display(); 
    bptr=&d; 
    bptr->display(); 
} 

Sortie:

Displaying from base 
Displaying from derieved 

S'il vous plaît quelqu'un peut répondre à pourquoi un pointeur de classe de base peut pointer la fonction membre d'une classe dérivée et vice-versa est impossible, pourquoi?

+4

Ça sent comme les devoirs. –

+1

Vous devez corriger l'extrait de code. –

+4

Parce que ce sont des devoirs, alors au lieu de demander aux gens de fournir les réponses, dites-nous quelles sont vos propres réponses (ou ébauches/réponses partielles), puis posez des questions ou demandez aux gens de commenter ou de corriger votre réponse. – ChrisW

Répondre

4
  1. Faux. Cela signifie simplement que les classes dérivées doivent implémenter cette fonction. Vous pouvez toujours fournir une définition de la fonction, qui peut être appelée par Base::Function(). *

  2. Les tables virtuelles sont un moyen d'implémenter des fonctions virtuelles. (La norme n'impose pas cette méthode, cependant.) Lors d'un appel polymorphe, le compilateur recherchera la fonction dans la table de fonctions et appellera celle-ci, permettant la liaison à l'exécution. (La table est générée au moment de la compilation.)

  3. Voir ci-dessus. Leurs tailles changent car il y a plus de fonctions virtuelles. Cependant, les instances ne stockent pas de table, mais plutôt un pointeur vers la table, de sorte que la taille de la classe n'a qu'une seule augmentation de taille.

  4. Sounds like you need a book.

* Un exemple classique est ici:

struct IBase 
{ 
    virtual ~IBase(void) = 0; 
}; 

inline IBase::~IBase(void) {} 

Ce ne serait pas une classe abstraite sans fonction virtuelle pure, mais un destructor a besoin d'un définition (puisqu'elle sera appelée lorsque les classes dérivées seront détruites.)

2

1) Pas nécessairement. Il y a des moments où vous fournissez un corps pour des fonctions virtuelles pures

2) La fonction à appeler est déterminée au moment de l'exécution.

+0

Même si c'est incomplet, rien ici n'est faux. Pourquoi -1? – GManNickG

+0

Je me demande pourquoi cela a été downvoted, car c'est correct. –

+0

Parce qu'IMO ils ne sont pas appropriés/utiles réponses à la question: incomplète, sans explication ou exemple. – ChrisW

1
  1. Faux. Cela signifie seulement que les classes dérivées doivent implémenter la méthode et que la définition de la méthode (si présente) à ce niveau ne sera pas considérée comme un remplacement de la méthode virtuelle.
  2. La vtable est implémentée au moment de la compilation, mais utilisée lors de l'exécution. Le compilateur redirigera l'appel via vtable, et cela dépend du type d'exécution de l'objet (un pointeur vers la base a un type statique base*, mais peut pointer vers un objet de type derived lors de l'exécution). Vptrs sont des pointeurs vers un vtable, ils ne changent pas de taille. vtables sont des tables de pointeurs à code (peuvent pointer vers des méthodes ou vers un code d'adaptateur) et avoir une entrée pour chaque méthode virtuelle déclarée dans la classe.

Après la modification dans le code:

Le pointeur se réfère à un objet de type base lors du premier appel, mais il pointe vers un objet de type derived à la deuxième position d'appel. Le mécanisme de répartition dynamique (vtable) achemine l'appel à la méthode appropriée. Une implémentation courante, qui peut vous aider à comprendre, est que dans chaque classe qui déclare des fonctions virtuelles, le compilateur réserve de l'espace pour un pointeur vers une table virtuelle et génère également la table virtuelle elle-même, où elle ajoute des pointeurs à la définition de chaque méthode virtuelle. La disposition de la mémoire de l'objet a seulement ce pointeur supplémentaire.

Lorsqu'une classe dérivée remplace l'une des méthodes de classe de base, le compilateur génère une vtable différente avec des pointeurs vers les remplaçants finaux à ce niveau. La disposition de la mémoire de la base et de la classe dérivée coïncide dans la sous-objet base (généralement le début), mais la valeur du vptr d'un objet base pointe vers la vtable de base, tandis que la valeur du vptr dans l'objet derived pointera vers le vtable dérivé.

Lorsque le compilateur voit un appel comme bptr->display(), il vérifie la définition de la classe de base, et voit qu'il est la première méthode virtuelle, puis il redirige l'appel comme: bptr->hidden_vptr[0](). Si le pointeur fait référence à une instance de base réelle, ce sera un pointeur vers base::display, tandis que dans le cas d'une instance derived, il pointera sur derived::display.

Notez qu'il y a beaucoup d'ondulations de la main dans cette réponse. Tout ceci est défini par l'implémentation (le langage ne spécifie pas le mécanisme de répartition) et, dans la plupart des cas, le mécanisme de répartition est plus complexe. Par exemple, lorsque l'héritage multiple a lieu, la vtable ne pointera pas directement sur le contourneur final, mais sur un bloc adaptateur de code qui réinitialise le premier paramètre implicite this, car le sous-objet base de tous sauf le premier est désaligné avec le objet le plus dérivé en mémoire - cela dépasse de loin la portée de la question, rappelez-vous simplement que cette réponse est une idée grossière et qu'il y a une complexité supplémentaire dans les systèmes réels.

1

Cette déclaration est valable

Pas exactement: il pourrait avoir un corps. Une définition plus précise est "Chaque fois que nous définissons une méthode comme étant purement virtuelle, cela signifie que la méthode doit être définie (redéfinie) dans une sous-classe concrète."

Et quel est le concept de la liaison dynamique? Je veux dire que si le compilateur optimise le code en utilisant les VTABLE et les VPTR, alors comment est ce polymorphisme d'exécution?

Si vous avez une instance d'une superclasse (par exemple forme) lors de l'exécution, vous ne savez pas/pas forcément besoin que de ses sous-classes (par exemple Circle ou Square), il est.

Qu'est-ce que VTABLES AND VPTRs et comment leurs tailles changent-elles?

Il y a un vtable par classe (pour toute classe qui a une ou plusieurs méthodes virtuelles). La vtable contient des pointeurs vers les adresses des méthodes virtuelles de la classe.

Il y a un vptr par objet (pour tout objet possédant une ou plusieurs méthodes virtuelles). Le vptr pointe vers la vtable pour la classe de cet objet.

La taille de vtable augmente avec le nombre de fonctions virtuelles de la classe. La taille du vptr est probablement constante.

S'il vous plaît quelqu'un peut-il répondre pourquoi un pointeur de classe de base peut pointer la fonction membre d'une classe dérivée et vice-versa n'est pas possible, pourquoi?

Si vous voulez appeler la fonction de la classe de base alors (car il est virtuel, et le comportement par défaut virtuel est d'appeler la version la plus dérivée via le VPTR/vtable) alors vous devez dire explicitement, par exemple comme ceci:

bptr->base::display(); 
Questions connexes