2009-02-26 5 views
5

J'ai une classe de base et une classe dérivée. Chaque classe a un fichier .h et un fichier .cpp.dynamic_cast échoue

que je fais dynamic_cast de l'objet de classe de base à la classe dérivée dans le code suivant:

fichiers h:

class Base 
{ 
    public: 
    Base(); 
    virtual ~Base(); 
}; 

class Derived : public Base 
{ 
    public: 
    Derived(){}; 
    void foo(); 
}; 

class Another 
{ 
    public: 
    Another(){}; 
    void bar(Base* pointerToBaseObject); 
}; 

fichiers cpp:

Base::Base() 
{ 
    //do something.... 
} 
Base::~Base() 
{ 
    //do something.... 
} 
void Derived::foo() 
{ 
    Another a; 
    a.bar(this); 
} 
void Another::bar(Base* pointerToBaseObject) 
{ 
    dynamic_cast<Derived*>(pointerToBaseObject) 
} 

De quelque raison étrange , la diffusion échoue (renvoie NULL). Cependant, la conversion réussit si je déplace l'implémentation du constructeur de la classe Derived de .h vers le fichier .cpp.

Quelle est la cause?

Le compilateur est gcc 3.1, sous Linux-SUSE. BTW, je vois ce comportement uniquement sur cette plate-forme, et le même code fonctionne très bien dans Visual Studio.

+0

peut-être est un bug avec gcc 3.1? essayez l'option "-fdump-class-hierarchy" et regardez si elle crée un vtable pour vos deux classes –

Répondre

5

Le code, tel que publié, ne doit pas échouer, à condition que vous ayez une fonction virtuelle dans la classe de base (comme litb souligné). Mais je crois que chaque compilateur actuel génère un type d'erreur "La classe de base n'est pas polymorphe" si ce n'est pas le cas, ce qui ne sera probablement pas le problème. La seule chose à laquelle je peux penser est qu'en raison d'un bogue bizarre, tout devient inline et aucun vtable n'est généré. Mais si vous placez le constructeur dans le fichier C++, le compilateur décide de ne pas tout aligner, ce qui déclenche la création d'un vtable, ce qui fait que votre distribution fonctionne.

Mais cela est très sauvage devinettes, et je ne pense pas que le compilateur aurait une telle erreur en elle (?)

Si vous voulez une réponse définitive, poster plus de code. Et le compilateur/plate-forme utilisée.

EDIT: En voyant le code mis à jour

Je pense que vous devriez au moins Dérive Dérivé de base;) (je suppose que c'est une faute de frappe)

Mais après avoir vu le code, la seule chose que je peux penser est que gcc (à tort) tout insère et ne génère pas de vtable pour Derived. Pour ce que ça vaut, ça marche bien compilé avec gcc 4.0

3.1 a plus de 7 ans maintenant ... s'il y a une possibilité de mise à niveau, je serais prêt pour cela.

7

Avez-vous une fonction virtuelle dans Base? Cela ne fonctionnera pas autrement. Si rien d'autre, rend son dtor virtuel.

Je ne sais pas s'il a déjà été demandé par l'autre gars qui a supprimé sa réponse, mais je crois que c'était quelque chose de différent: Est-ce que vous faites le dynamic_cast du constructeur des bases? Si oui, cela ne fonctionnera pas. Le compilateur pensera que la base est le type le plus dérivé, similaire à quand vous appelez une fonction virtuelle et il finit par appeler la version de la base.

+0

J'ai des fonctions virtuelles dans Base. –

3

Rendez le destructeur virtuel et placez-le (ou au moins une méthode virtuelle) dans le fichier .cpp.

Certains compilateurs (lire: gcc) recherchent le corps de la méthode virtuelle non-inline rencontré en premier et l'utilisent pour décider où placer la table de méthode virtuelle.Si vous n'avez aucune méthode virtuelle avec des corps dans un fichier .cpp, la table de méthode virtuelle n'est pas créée.

Vous devez disposer d'au moins une méthode virtuelle pour que dynamic_cast fonctionne. La distribution dynamique utilise la table pour comprendre les informations de type et aucune table n'est créée s'il n'existe aucune méthode virtuelle.

Si vous avez une classe que vous pensez être sous-classée et qu'elle a un destructeur ou si la classe a des variables d'instance qui sont des classes avec des destructeurs, alors vous voudrez vraiment rendre votre destructeur virtuel (même s'il a un corps vide). Sinon, le nettoyage attendu ne se produira pas pour les instances de sous-classe.

0

Faites-vous cela dans Visual C++? Je pense que vous devez activer les informations de type à l'exécution (RTTI) dans le paramètre du compilateur pour que cela fonctionne.

Ne me brûlez pas si je me trompe. Cela fait longtemps que j'ai utilisé le C++ !!!

0

En regardant votre code, je ne vois aucun héritage. Avez-vous oublié de faire cela? Dérivé ne dérive de rien.

0

Dans le code que vous avez publié Derived n'est pas dérivé de Base.

Edit: Pour votre information, le code modifié fonctionne très bien avec g ++ 3.4.5