8 votes

Détails de bas niveau de l'héritage et du polymorphisme

Cette question est l'un des grands doutes qui plane dans ma tête et il est également difficile de le décrire en termes de mots. Parfois, elle semble évidente et parfois, elle est difficile à résoudre :

class Base{
public:
     int a\_number;

     Base(){}
     virtual void function1() {}
     virtual void function2() {}
     void function3() {}
};

class Derived:public Base{
public:
     Derived():Base() {}
     void function1() {cout << "Derived from Base" << endl; 
     virtual void function4() {cout << "Only in derived" << endl;}
};

int main(){

      Derived \*der\_ptr = new Derived();
      Base \*b\_ptr = der\_ptr;  // As just address is being passed , b\_ptr points to derived                object

      b\_ptr -> function4(); // Will Give Compilation ERROR!!

      b\_ptr -> function1(); // Calls the Derived class overridden method

      return 0;

}

Q1. Bien que b_ptr pointe vers un objet dérivé, à quel VTABLE accède-t-il et COMMENT ? car b_ptr -> function4() donne une erreur de compilation. Ou est-ce que b_ptr ne peut accéder qu'à la taille de la classe de base VTABLE dans le VTABLE dérivé ?

Q2. Étant donné que la disposition de la mémoire de la classe dérivée doit être (Base,Derived) , le VTABLE de la classe Base est-il également inclus dans la disposition de la mémoire de la classe dérivée ?

Q3. Puisque la fonction1 et la fonction2 de la classe de base Vtable pointe vers l'implémentation de la classe de base et la fonction2 de la classe dérivée pointe vers la fonction2 de la classe de base, y a-t-il vraiment un besoin de VTABLE dans la classe de base ? (C'est peut-être la question la plus stupide que je puisse poser, mais je suis toujours dans le doute à ce sujet dans mon état actuel et la réponse doit être liée à la réponse de Q1 :) )

Veuillez commenter.

Merci de votre patience.

1voto

aschepler Points 23731

Tout cela dépend de l'implémentation. Mais voici les réponses pour la façon la plus simple d'utiliser "vtables".

El Base a un pointeur vtable, donc la représentation sous-jacente est quelque chose comme ce pseudo-code :

struct Base {
  void** __vtable;
  int a_number;
};
void* __Base_vtable[] = { &Base::function1, &Base::function2 };
void __Base_ctor( struct Base* this_ptr ) { this_ptr->__vtable = __Base_vtable; }

El Derived comprend une classe Base classe sous-objet. Puisqu'il y a une place pour une vtable, Derived n'a pas besoin d'en ajouter un autre.

struct Derived {
  struct Base __base;
};
void* __Derived_vtable[] =
  { &Derived::function1, &Base::function2, &Derived::function4 };
void __Derived_ctor( struct Derived* this_ptr ) {
  __Base_ctor( &this_ptr->__base );
  this_ptr->__base.__vtable = __Derived_vtable;
}

La "vtable de la classe de base", __Base_vtable dans mon pseudo-code, est nécessaire au cas où quelqu'un essaierait de new Base(); ou Base obj; .

Tout ce qui précède se complique lorsque l'héritage multiple ou l'héritage virtuel est impliqué.....

Pour la ligne b_ptr -> function4(); Il s'agit d'une erreur de compilation, qui n'a rien à voir avec vtables. Lorsque vous effectuez un cast vers un Base* vous ne pouvez utiliser ce pointeur que de la manière définie par la directive class Base (parce que le compilateur ne "sait" plus si c'est vraiment un Derived , a Base ou une autre classe). Si Derived a un membre de données qui lui est propre, vous ne pouvez pas y accéder par le biais de ce pointeur. Si Derived a une fonction membre qui lui est propre, virtuelle ou non, vous ne pouvez pas y accéder via ce pointeur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X