web-dev-qa-db-fra.com

dynamic_cast de "void *"

Selon this , void* n’a pas d’information RTTI, donc transtyper à partir de void* n’est pas légal et cela a du sens.

Si je me souviens bien, dynamic_cast de void* travaillait sur gcc. 

Pouvez-vous s'il vous plaît clarifier la question.

33
dimba

dynamic_cast ne fonctionne que sur les types polymorphes, c'est-à-dire les classes contenant des fonctions virtuelles.

Dans gcc vous pouvez dynamic_cast à void* mais pas à partir de :

struct S
{
    virtual ~S() {}
};

int main()
{
    S* p = new S();
    void* v = dynamic_cast<void*>(p);
    S* p1 = dynamic_cast<S*>(v); // gives an error
}
40
vitaut

Dans 5.2.7 - Dynamic cast [expr.dynamic.cast], il est indiqué que pour dynamic_cast<T>(v):

  • Si T est un type de pointeur, v doit être la valeur d'un pointeur pour compléter le type de classe.
  • Si T est un type de référence, v doit être une lvalue d'un type de classe complet (merci, usta, d'avoir commenté le manquement)

...

  • Sinon, v doit être un pointeur ou une valeur de type polymorphe 

Donc, non, un (void*) valeur n'est pas autorisé.

Pensons à ce que votre demande pourrait signifier: disons que vous avez un pointeur qui est vraiment à un Derived1*, mais que le code dynamic_cast- ne sait que c'est un void*. Supposons que vous essayez de le transtyper en un Derived2*, où les deux classes dérivées ont une base commune. Superficiellement, vous pourriez penser que tous les pointeurs pointeraient vers le même objet Base, qui contiendrait un pointeur sur la table de répartition virtuelle et le RTTI pertinents, de sorte que tout puisse rester ensemble. Cependant, considérez que les classes dérivées peuvent avoir plusieurs classes de base et que, par conséquent, le sous-objet de classe Base nécessaire pourrait ne pas être celui sur lequel pointe le Derived* - disponible uniquement en tant que void* -. Ça ne marcherait pas. Conclusion: le compilateur a besoin de connaître ces types pour pouvoir ajuster les pointeurs en fonction des types impliqués.

 Derived1 * -----> [AnotherBase] 
 [[VDT] Base] <- mais, il faut un pointeur pour démarrer 
 [membres supplémentaires] ce sous-objet pour dynamic_cast 

(Certaines réponses parlent de la nécessité que le pointeur que vous nommez soit de type polymorphe, avec des fonctions virtuelles. C'est tout à fait valable, mais un peu trompeur. Comme vous pouvez le voir ci-dessus, même si le void* est d'un tel type cela ne fonctionnerait toujours pas de manière fiable sans les informations de type complètes, car le vrai problème est que void* pointe probablement vers le début de l'objet dérivé, alors que vous avez besoin d'un pointeur sur le sous-objet de la classe de base à partir duquel le type transtypé dérive.)

15
Tony Delroy

Il est vrai que void* ne peut pas être dynamically_casted.

Vous vous souvenez probablement mal. Avec g ++ 4.5 et le code suivant

struct A {
    virtual ~A();
};

int main() {
    A a;
    void *p = &a;
    A* pa = dynamic_cast<A*>(p);
}

Je reçois l'erreur suivante:

ne peut pas dynamic_cast 'p' (de type 'void *') taper 'struct A *' (source n'est pas un pointeur sur class)

4
Motti

Je suppose que vous confondez avec dynamic_cast à void*. Cela est légal et obtient le pointeur sur l'objet de classe le plus dérivé.

dynamic_cast from void* est illégal - le type utilisé doit être polymorphe - contient au moins une fonction virtuelle (le destructeur virtuel compte également).

1
sharptooth

Vous pouvez convertir un pointeur en type polymorphe en void *, mais pas l'inverse.

0
usta