Maison >développement back-end >C++ >Pourquoi l'appel d'une fonction virtuelle dans un constructeur de classe de base entraîne-t-il l'utilisation de l'implémentation de la classe de base ?

Pourquoi l'appel d'une fonction virtuelle dans un constructeur de classe de base entraîne-t-il l'utilisation de l'implémentation de la classe de base ?

Barbara Streisand
Barbara Streisandoriginal
2024-12-21 02:03:15823parcourir

Why Does Calling a Virtual Function in a Base Class Constructor Result in the Base Class Implementation Being Used?

Remplacer les fonctions virtuelles dans les constructeurs

Considérez l'extrait de code suivant :

#include <iostream>
struct base {
  virtual const int value() const {
    return 0;
  }

  base() { // Default constructor
    std::cout << value() << std::endl;
  }
};

struct derived : public base {
  virtual const int value() const {
    return 1;
  }
};

int main() {
  derived d; // Declares an instance of the derived class
}

Lorsque nous exécutons ce code, il imprime 0 au lieu du 1 attendu. Pourquoi ?

Virtuel Appel de fonction pendant la construction

Lorsqu'un constructeur de classe de base appelle une fonction virtuelle dans le constructeur, la fonction virtuelle est appelée sur l'instance de classe de base plutôt que sur l'instance de classe dérivée. Ceci est le résultat du processus de « maturation » de l'objet pendant la construction.

  • Maturation : Au fur et à mesure qu'un objet est construit, il commence par les constructeurs de la classe de base et progressivement « mûrit » " dans le type de classe dérivé.

Dans notre exemple, le constructeur de base appelle value() lorsque l'objet est partiellement construit. À ce stade, l’objet n’a pas encore « mûri » pour devenir un objet dérivé. Ainsi, l'implémentation de base originale de value() est appelée.

Comment résoudre le problème

Pour que le code s'imprime 1, vous pouvez éviter d'appeler la fonction virtuelle dans le constructeur. Ceci peut être réalisé par :

  1. Utilisation d'un pointeur : Appelez la fonction virtuelle à partir d'un pointeur ou d'une référence à la classe de base au lieu de directement à partir de sa fonction membre :

    base* b = new derived();
    b->value(); // Calls the derived class implementation
    
    delete b;
  2. Utilisation d'une liste d'initialisation de membre : Utiliser un membre liste d'initialisation pour spécifier explicitement la valeur de la fonction virtuelle dans le constructeur :

    derived d : base() { } // Initializes `base()` and the virtual function
                           // call to occur within the constructor
  3. Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn