[Notes C ++] Structure C ++ et ordre d'exécution du destructeur

Il n'y a pas si longtemps, un ami a rencontré un poste de développement back-end recruté par Tencent et lui a parlé. Il a dit que le côté de Tencent est encore plus basique. Il y a plus de questions sur le C ++, les systèmes d'exploitation, les réseaux et les algorithmes, même s'il s'agit de recrutement social. . Parmi eux, il y a une question sur l'ordre de construction et de destruction du C ++ en matière d'héritage virtuel. Je n'y prête pas beaucoup d'attention en temps normal, donc cela a vraiment embarrassé de nombreux intervieweurs. Mon ami est l'un d'entre eux, il est donc nécessaire de le résumer. .

En C ++, lorsqu'un objet de classe est créé, le compilateur appellera automatiquement quelque chose appelé constructeur. Nous savons que les classes et les classes C ++ sont liées dans de nombreux cas, comme l'héritage, la composition, etc. Cette rubrique est décrite dans l'article Comprendre les diagrammes de classes UML (veuillez me pousser). Cet article résume principalement la séquence de construction et de destruction dans diverses situations à travers des exemples.

hériter

Scénario: La classe B hérite de deux classes parentes A et C. Le constructeur et le destructeur de chaque classe sont très simples, il suffit d'imprimer le nom de la fonction correspondante pour observer l'ordre d'exécution de la construction et du destructeur.

#include <iostream>

using namespace std;

class A
{    
    public:        
        A(){cout << "A()" << endl;}       
        ~A(){cout << "~A()" << endl;}
};

class C
{    
    public:        
        C(){cout << "C()" << endl;}        
        ~C(){cout << "~C()" << endl;}
};

class B: public A, public C
{    
    public:        
        B(){cout << "B()" << endl;}        
        ~B(){cout << "~B()" << endl;}
};

int main(int argc, char const *argv[])
{    
    B b;    
    return 0;
}
bogon:dataStructure lizhong$ ./t
A()
C()
B()
~B()
~C()
~A()

Cela peut être vu à partir des résultats en cours d'exécution: lors de la création d'un objet de sous-classe, exécutez d'abord le constructeur de la classe parente, puis exécutez son propre constructeur. Si la sous-classe hérite de plusieurs classes parentes, la classe parente sera appelée de gauche à droite dans l'ordre d'héritage. Constructeur (dans cet exemple, construisez d'abord A, puis construisez C), l'ordre de destruction est opposé à l'ordre de construction.

Nous savons également qu'il existe un autre type d'héritage appelé héritage virtuel. Jetons un coup d'œil à l'ordre de construction et de destruction dans ce cas.

#include <iostream>

using namespace std;

class A
{    
    public:        
        A(){cout << "A()" << endl;}       
        ~A(){cout << "~A()" << endl;}
};

class C
{    
    public:        
        C(){cout << "C()" << endl;}        
        ~C(){cout << "~C()" << endl;}
};

class B: public A, public C
{    
    public:        
        B(){cout << "B()" << endl;}        
        ~B(){cout << "~B()" << endl;}
};

int main(int argc, char const *argv[])
{    
    B b;    
    return 0;
}
bogon:dataStructure lizhong$ ./t
C()
A()
B()
~B()
~A()
~C()

On peut voir que l'ordre de l'héritage virtuel et de la construction et de la destruction de l'héritage général est encore un peu différent. L'ordre de construction de la classe parente a changé. Le constructeur C de l'héritage virtuel est exécuté en premier, puis A. Enfin, son propre constructeur est appelé, et l'ordre de destruction est opposé à l'ordre de construction.

Les membres incluent d'autres membres d'objet de classe

Scénario: La classe B contient des membres d'objets de classe A et d'objets de classe C, et dans la classe B, l'ordre de déclaration de ses membres est de déclarer d'abord c, puis a. Jetez un œil à l'ordre d'exécution du constructeur et du destructeur lors de la création d'un objet de classe B.

#include <iostream>

using namespace std;

class A
{    
    public:        
        A(){cout << "A()" << endl;}       
        ~A(){cout << "~A()" << endl;}
};

class C
{    
    public:        
        C(){cout << "C()" << endl;}        
        ~C(){cout << "~C()" << endl;}
};

class B
{    
    public:        
        B():a(A()), c(C()) {cout << "B()" << endl;}        
        ~B(){cout << "~B()" << endl;}
        C c;  
        A a;
};

int main(int argc, char const *argv[])
{    
    B b;    
    return 0;
}
bogon:dataStructure lizhong$ ./t
C()
A()
B()
~B()
~A()
~C()

Les résultats de l'opération sont visibles: lors de la création d'un objet de classe B b, exécutez d'abord le constructeur de la classe à laquelle appartient son objet membre, puis exécutez son propre constructeur. S'il y a plusieurs membres d'objet de classe, appelez la structure de classe correspondante dans l'ordre de déclaration Fonction (dans cet exemple, construisez d'abord l'objet de type C c, puis construisez l'objet de type A a), l'ordre de destruction est opposé à l'ordre de construction.

Membres de l'héritage et de l'objet de classe

Scénario: la classe B hérite de deux classes parentes A et C et la classe B a un objet membre de la classe X. Observez l'ordre d'exécution des fonctions de construction et de destruction.

#include <iostream>
using namespace std;

class A
{
    public:
        A(){cout << "A()" << endl;}
        ~A(){cout << "~A()" << endl;}
};

class C
{
    public:
        C(){cout << "C()" << endl;}
        ~C(){cout << "~C()" << endl;}
};

class X
{
    public:
        X(){cout << "X()" << endl;}
        ~X(){cout << "~X()" << endl;}
};

class B: public A, public  C
{
    public:
        B(){cout << "B()" << endl;}
        ~B(){cout << "~B()" << endl;}
        X x;
};

int main(int argc, char const *argv[])
{
    B b;
    return 0;
}
bogon:dataStructure lizhong$ ./t
A()
C()
X()
B()
~B()
~X()
~C()
~A()

Les résultats de l'opération sont visibles: lorsque la classe est construite, elle appellera d'abord le constructeur de la classe parente de gauche à droite, puis appellera le constructeur membre de l'objet de classe, et enfin appeler son propre constructeur. L'ordre de destruction est opposé à l'ordre de construction.

Lecture recommandée:

Soigneusement organisé | Catalogue d'articles historiques sur les produits secs
[bien-être] J'ai rassemblé le partage de vidéos de cours en boutique en ligne (partie 1)
[structure de données et algorithme] traversée d'arbre binaire facile à comprendre
[structure de données et algorithme] arbre de recherche binaire facile à comprendre

Focus sur le partage de résumé des connaissances de la pile de technologie d'arrière-plan du serveur

Bienvenue à prêter attention à la communication et au progrès commun

[Notes C ++] Structure C ++ et ordre d'exécution du destructeur

Codage

Le fermier de code a la bonne façon de vous fournir des articles techniques faciles à comprendre pour faciliter la technologie!

Je suppose que tu aimes

Origine blog.51cto.com/15006953/2552126
conseillé
Classement