2014-07-11 2 views
0

Dans une situation où une classe de base et une classe dérivée ont une fonction membre nommée de manière identique, pourquoi type cast la classe dérivée comme une classe de base et appelle le membre produit effectivement une sortie correspondant à la classe de base? Je pensais que la définition de la fonction membre dans la classe dérivée écrasait la fonction dans la classe de base.La classe dérivée de classe de base conduit à un appel de fonction membre de classe de base

Dans le code ci-dessous, il existe une classe de base myClass et une classe dérivée newClass. Les deux myClass et newClass mettre en œuvre une fonction membre appelée serialize().

Lorsque l'instance insta de type newClass est catalogué comme myClass, la fonction de membre serialize() qui est appelé appartient à la classe de base myClass et non la classe dérivée. Les adresses sont les mêmes pour les deux appels, ce qui indique qu'il n'y a pas d'événement de copie mystérieux qui se produit, et que c'est en effet quelque chose à voir avec le cast.

Pourquoi cela se produit-il?

Voici le code qui reproduit ce comportement.

#include <iostream> 
#include <typeinfo> 
#include <string> 
#include <sstream> 
#include <vector> 

class myClass{ 

friend void Inspect(myClass&); 
private: 
    int data; 
    std::string name; 
public: 
    myClass(std::string _name, int _d): 
     name(_name), 
     data(_d){} 
    std::vector<double> v; 
    std::string serialize(); 

}; 


std::string myClass::serialize(){ 
    std::ostringstream retstream; 
    retstream << "string name " << name << "\n"; 
    retstream << "int data " << data << "\n"; 
    retstream << "vector<double> v "; 
    for (unsigned int i = 0; i < v.size(); i++){ 
     retstream << v[i] << " "; 
    } 
    retstream << "\n"; 
    retstream << "---" << std::endl; 
    retstream << "address " << this << "\n"; 
    return retstream.str(); 
} 

class newClass: public myClass{ 

private: 
    int data2; 
    std::string name; 
public: 
    newClass(std::string _name, int _d): 
     myClass(_name, _d), name(_name), data2(_d){} 
    std::string serialize(); 
}; 


std::string newClass::serialize(){ 
    std::ostringstream retstream; 
    retstream << "string name " << name << "\n"; 
    retstream << "address " << this << "\n"; 
    return retstream.str(); 
} 


template <class T> 
void Inspect(T & instance){ 
//#if defined(DDEBUG) || defined(DDDEBUG) 
    std::cout << "Inspecting " << typeid(instance).name() << "\n"; 
    std::cout << instance.serialize() << "\n"; 
    std::cout << &instance << "\n"; 
//#endif 
} 


int main(){ 
newClass insta("newClass_instance-1", 2); 
Inspect<myClass>(insta); 
Inspect<newClass>(insta); 
return 0;} 

sur la compilation de ce code et l'exécuter, on obtient cette sortie:

Inspecting 7myClass 
string name newClass_instance-1 
int data 2 
vector<double> v 
--- 
address 0x7fff73529fb0 

0x7fff73529fb0 
Inspecting 8newClass 
string name newClass_instance-1 
address 0x7fff73529fb0 

0x7fff73529fb0 

Mes informations compilateur est g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

+2

Parce que la fonction membre n'est pas "virtuelle". – juanchopanza

+0

Donc, ce n'est pas une bizarrerie de mon compilateur et ce comportement persistera sur différents systèmes? – CCG

+1

Oui, c'est correct. – juanchopanza

Répondre

2

le déclarer comme virtuel. Déclarer un membre comme virtuel ajoute un objet vtable caché à votre classe. Le vtable est fondamentalement un tableau de pointeurs sur les fonctions (chaque compilateur implémentera cela différemment). Lorsque vous appelez une fonction virtuelle, vtable est utilisé pour appeler la fonction. Lorsque vous appelez une fonction de classe non virtuelle, le type de la classe est utilisé pour appeler la fonction.

class Base { 
    virtual void VirtualFunc() { } 
    void Func() { } 
}; 
class Derived : public Base { 
    void VirtualFunc() override { } 
    void Func() override { } 
}; 

Base* pBase = new Base(); 

pBase->VirtualFunc();      // calls Base's VirtualFunc 
((Derived*)pBase)->VirtualFunc();   // calls Base's VirtualFunc 
pBase->Derived::VirtualFunc();    // wont compile 
((Derived*)pBase)->Derived::VirtualFunc(); // will crash 
pBase->Func();        // calls Base's Func 
((Derived*)pBase)->Func();     // will crash 

Derived* pDerived = new Derived(); 

pDerived->VirtualFunc();     // calls Derived's VirtualFunc 
((Base*)pDerived)->VirtualFunc();   // calls Derived's VirtualFunc 
pDerived->Base::VirtualFunc();    // calls Base's VirtualFunc 
((Base*)pDerived)->Base::VirtualFunc();  // calls Base's VirtualFunc 
pDerived->Func();       // calls Derived's Func 
((Base*)pDerived)->Func();     // calls Base's Func 
+0

Merci pour cela. Cela aide vraiment! – CCG

Questions connexes