2017-02-16 1 views
2

Je regarde un exemple de comportement des fonctions virtuelles. Compte tenu de ce code de test, j'ai quelques questions quant à son comportement.Incompatibilité de signature de fonction virtuelle et son comportement

class A 
{ 
public: 
    A(int x) 
    { 
     cout << "In A Constructor" << endl; 
     print(); 
    } 
    ~A(){ 
     cout << "In A Destructor" << endl; 
     delete _val; 
    } 
    virtual void print() { cout << "A." << endl; } 
private: 
    char* _val; 
}; 

class B: public A 
{ 
public: 
    B(int x, int y) : A(x) 
    { 
     _dVal = new char[y]; 
     cout << "In B Constructor 1" << endl; 
     print(); 
    } 
    B() : A(0) 
    { 
     _dVal = new char[1]; 
     cout << "In B Constructor 2" << endl; 
     print(); 
    } 
    ~B(){ 
     cout << "In B Destructor" << endl; 
     delete _dVal; 
    } 
    void print() { cout << "B" << endl; } 
private: 
    char* _dVal; 
}; 

int main(int argc, char** argv) { 
    A* p1 = new B(); 
    p1->print(); 
    delete p1; 
    return 0; 
} 

La sortie est:

In A Constructor 
A. 
In B Constructor 2 
B 
B 
In A Destructor 

1) Pourquoi l'impression appelé pour la classe B si la classe A est le seul désignant comme une fonction virtuelle et il est appelé par déréférencer (->)? 2) Pourquoi le destructeur de B n'est-il jamais appelé si le constructeur est appelé?

+1

Si la fonction est virtuelle dans la classe de base, elle est également virtuelle dans toutes les classes dérivées. Idem pour le destructeur. –

+1

Une question par question s'il vous plaît. –

Répondre

4

1) Pourquoi l'impression est-elle appelée pour la classe B si la classe A est la seule à la désigner comme une fonction virtuelle et qu'elle est appelée par déréférence (->)?

C'est ce que les fonctions virtuelles sont censées faire. Le pointeur p1 est de type A* mais pointe vers un objet de type B en fait. Et cette liaison dynamique ne se produit que lorsqu'une classe dérivée est gérée à l'aide d'un pointeur ou d'une référence à la classe de base.

Notez également que la fonction primordiale dans la classe dérivée est également virtual (si le mot-clé est utilisé virtuel ou non dans sa déclaration).

2) Pourquoi le destructeur de B n'est-il jamais appelé si le constructeur est en fait appelé?

Le destructor de B n'est pas appelé parce que vous n'êtes pas déclarer la destructor de classe de base (à savoir A::~A) comme virtual destructor. Le comportement n'est pas défini pour ce cas. Le constructeur de B est appelé car vous construisez B explicitement par new B().

+0

Intéressant. Puisque le comportement n'est pas défini, cela signifie-t-il que _dVal de la classe B deviendrait un oprhan et provoquerait alors une fuite de mémoire? – w0ffen

+0

@ user49096 Du résultat que vous avez observé, oui. Notez que c'est indéterminé, tout est possible. – songyuanyao

+0

@ user49096 "Puisque le comportement est indéfini, est-ce que cela signifie" non, cela signifie que ce qui se passe n'est pas défini, indéfini, inconnu ... – curiousguy