web-dev-qa-db-fra.com

Quel est l'ordre dans lequel les destructeurs et les constructeurs sont appelés en C ++

Quel est l'ordre dans lequel les destructeurs et les constructeurs sont appelés en C++? Utilisation des exemples de certaines classes de base et classes dérivées

46
hozefam

L'ordre est:

  1. Constructeur de base
  2. Constructeur dérivé
  3. Destructeur dérivé
  4. Destructeur de base

Exemple:

class B
{
public:
  B()
  {  
    cout<<"Construct B"<<endl;
  }

  virtual ~B()
  {
    cout<<"Destruct B"<<endl;
  }
};

class D : public B
{
public:
  D()
  {  
    cout<<"Construct D"<<endl;
  }

  virtual ~D()
  {
    cout<<"Destruct D"<<endl;
  }
};



int main(int argc, char **argv)
{
  D d; 
  return 0;
}

sortie de l'exemple:

Construire B

Construire D

Destruct D

Destruct B

Plusieurs niveaux d'héritage fonctionnent comme une pile:

Si vous envisagez de pousser un élément sur la pile comme construction et de le retirer comme destruction, vous pouvez regarder plusieurs niveaux d'héritage comme une pile.

Cela fonctionne pour n'importe quel nombre de niveaux.

Exemple D2 dérive de D dérive de B.

Appuyez sur B sur la pile, appuyez sur D sur la pile, appuyez sur D2 sur la pile. L'ordre de construction est donc B, D, D2. Ensuite, pour découvrir l'ordre de destruction, commencez à apparaître. D2, D, B

Exemples plus compliqués:

Pour des exemples plus compliqués, veuillez consulter le lien fourni par @JaredPar

60
Brian R. Bondy

Une description détaillée de ces événements, y compris l'héritage virtuel et multiple, est disponible sur le C++ FAQ Lite. Section 25.14 et 25.15

https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order

21
JaredPar

Gardez également à l'esprit que si les éléments du tableau sont construits en premier -> dernier, ils sont détruits dans l'ordre inverse: dernier -> premier.

10
Ferruccio

Je dois ajouter aux réponses précédentes car tout le monde semble l'ignorer

Lorsque vous avez une instance de classe dérivée étant créée, il est vrai que le code à l'intérieur le constructeur de la base sera appelé avant le code à l'intérieur le constructeur du dérivé, mais gardez à l'esprit que le dérivé est toujours techniquement "créé"avant le base.

Et quand vous avez le destructeur de classe dérivé appelé, il est vrai que le code à l'intérieur le destructeur dérivé est appelé avant le code à l'intérieur le destructeur de base, mais gardez également à l'esprit que le base est détruitavant le dérivé.

Quand je dis créé/détruit je fais en fait référence à alloué/désalloué.

Si vous regardez la disposition de la mémoire de ces instances, vous verrez que l'instance dérivée compose l'instance de base. Par exemple:

Mémoire dérivée: 0x00001110 à 0x00001120

Mémoire de base: 0x00001114 à 0x00001118

Par conséquent, la classe dérivée doit être allouée AVANT la base de la construction. Et la classe dérivée doit être désallouée APRÈS la base de la destruction.

Si vous disposez du code suivant:

class Base 
{
public:
    Base()
    {
        std::cout << "\n  Base created";
    }
    virtual ~Base()
    {
        std::cout << "\n  Base destroyed";
    }
}

class Derived : public Base 
{
public:
    Derived()
    // Derived is allocated here 
    // then Base constructor is called to allocate base and prepare it
    {
        std::cout << "\n  Derived created";
    }
    ~Derived()
    {
        std::cout << "\n  Derived destroyed";
    }   
    // Base destructor is called here
    // then Derived is deallocated
}

Donc, si vous avez créé Derived d; et si elle était hors de portée, vous obtiendrez la sortie dans la réponse de @ Brian. Mais le comportement de l'objet en mémoire n'est pas vraiment dans le même ordre, il ressemble plutôt à ceci:

Construction:

  1. Dérivé alloué

  2. Base allouée

  3. Constructeur de base appelé

  4. Constructeur dérivé appelé

Destruction:

  1. Destructeur dérivé appelé

  2. Destructeur de base appelé

  3. Base désallouée

  4. Dérivé désaffecté

5
Everyone