Je suis assez confus avec le dynamic_cast
mot - clé en C ++.
struct A {
virtual void f() { }
};
struct B : public A { };
struct C { };
void f () {
A a;
B b;
A* ap = &b;
B* b1 = dynamic_cast<B*> (&a); // NULL, because 'a' is not a 'B'
B* b2 = dynamic_cast<B*> (ap); // 'b'
C* c = dynamic_cast<C*> (ap); // NULL.
A& ar = dynamic_cast<A&> (*ap); // Ok.
B& br = dynamic_cast<B&> (*ap); // Ok.
C& cr = dynamic_cast<C&> (*ap); // std::bad_cast
}
la définition dit:
Le
dynamic_cast
mot-clé convertit une donnée d'un pointeur ou d'un type de référence à un autre, en effectuant une vérification à l'exécution pour garantir la validité de la conversion
Pouvons-nous écrire un équivalent de dynamic_cast
C ++ en C pour que je puisse mieux comprendre les choses?
c++
dynamic-cast
Vijay
la source
la source
dynamic_cast<>
fonctionne dans les coulisses (ou combien de C ++ fonctionne), un bon livre (qui est aussi assez facile à lire pour quelque chose d'aussi technique) est "Inside the C ++ Object Model" de Lippman. Les livres "Design and Evolution of C ++" et "The C ++ Programming Language" de Stroustrup sont également de bonnes ressources, mais le livre de Lippman est dédié à la manière dont C ++ fonctionne "en coulisses".B* b2 = dynamic_cast<B*> (ap) // 'b'
?b2 is pointer to b
ou quoi?Réponses:
Voici un aperçu
static_cast<>
et endynamic_cast<>
particulier en ce qui concerne les pointeurs. Ceci est juste un aperçu de 101 niveaux, il ne couvre pas toutes les subtilités.static_cast <Type *> (ptr)
Cela prend le pointeur
ptr
et tente de le convertir en toute sécurité en un pointeur de typeType*
. Cette distribution est effectuée au moment de la compilation. Il n'effectuera le cast que si les types de type sont liés. Si les types ne sont pas liés, vous obtiendrez une erreur du compilateur. Par exemple:dynamic_cast <Type *> (ptr)
Cela tente à nouveau de prendre le pointeur
ptr
et de le convertir en toute sécurité en un pointeur de typeType*
. Mais ce cast est exécuté au moment de l'exécution, pas au moment de la compilation. Comme il s'agit d'un cast au moment de l'exécution, il est particulièrement utile lorsqu'il est combiné avec des classes polymorphes. En fait, dans les cas certiens, les classes doivent être polymorphes pour que la distribution soit légale.Les moulages peuvent aller dans l'une des deux directions suivantes: de la base au dérivé (B2D) ou du dérivé à la base (D2B). C'est assez simple pour voir comment les casts D2B fonctionneraient au moment de l'exécution. Soit
ptr
était dérivé de,Type
soit il ne l'était pas. Dans le cas des D2B dynamic_cast <>, les règles sont simples. Vous pouvez essayer de convertir n'importe quoi en autre chose, et si elleptr
est en fait dérivée deType
, vous récupérerez unType*
pointeurdynamic_cast
. Sinon, vous obtiendrez un pointeur NULL.Mais les lancers B2D sont un peu plus compliqués. Considérez le code suivant:
main()
ne peut pas dire quel type d'objetCreateRandom()
retournera, donc le cast de style CBar* bar = (Bar*)base;
n'est décidément pas de type sécurisé. Comment pouvez-vous résoudre ce problème? Une façon serait d'ajouter une fonction comme boolAreYouABar() const = 0;
à la classe de base et de retournertrue
deBar
etfalse
deFoo
. Mais il existe un autre moyen: utilisezdynamic_cast<>
:Les casts s'exécutent au moment de l'exécution et fonctionnent en interrogeant l'objet (pas besoin de s'inquiéter de savoir comment pour le moment), en lui demandant s'il est le type que nous recherchons. Si c'est le cas,
dynamic_cast<Type*>
renvoie un pointeur; sinon, il renvoie NULL.Pour que cette conversion de base en dérivé fonctionne avec
dynamic_cast<>
, Base, Foo et Bar doivent être ce que le Standard appelle des types polymorphes . Pour être de type polymorphe, votre classe doit avoir au moins unevirtual
fonction. Si vos classes ne sont pas des types polymorphes, l'utilisation de base à dérivée dedynamic_cast
ne sera pas compilée. Exemple:L'ajout d'une fonction virtuelle à la base, comme un dtor virtuel, rendra les types polymorphes Base et Der:
la source
Base* base = new Base;
, ledynamic_cast<Foo*>(base)
seraNULL
.dynamic_cast<Foo*>(base)
est nul en cas de aBase* base = new Base;
?base
n'est pas unFoo
. UnBase
pointeur peut pointer vers aFoo
, mais c'est toujours unFoo
, donc une distribution dynamique fonctionnera. Si vous le faitesBase* base = new Base
,base
est aBase
, pas aFoo
, vous ne pouvez donc pas le convertir dynamiquement en aFoo
.À moins que vous n'implémentiez votre propre RTTI roulé à la main (et en contournant celui du système), il n'est pas possible de l'implémenter
dynamic_cast
directement dans le code de niveau utilisateur C ++.dynamic_cast
est très lié au système RTTI de l'implémentation C ++.Mais, pour vous aider à comprendre RTTI (et donc
dynamic_cast
) plus, vous devriez lire l'en-<typeinfo>
tête et l'typeid
opérateur. Cela renvoie les informations de type correspondant à l'objet que vous avez sous la main, et vous pouvez demander diverses choses (limitées) à partir de ces objets d'informations de type.la source
dynamic_cast
sont très maigres. :-P Jouez simplement avec vous-même jusqu'à ce que vous compreniez. :-)Plus que du code en C, je pense qu'une définition anglaise pourrait suffire:
Étant donné une classe Base dont il existe une classe dérivée Derived,
dynamic_cast
convertira un pointeur Base en pointeur Derived si et seulement si l'objet réel pointé est en fait un objet Derived.Dans l'exemple, l'appel à
test
lie différents objets à une référence àBase
. En interne, la référence est descendue vers une référence àDerived
de manière sécurisée: la conversion descendante ne réussira que dans les cas où l'objet référencé est effectivement une instance deDerived
.la source
Ce qui suit n'est pas vraiment proche de ce que vous obtenez de C ++
dynamic_cast
en termes de vérification de type, mais peut-être que cela vous aidera à comprendre un peu mieux son objectif:la source
A
dynamic_cast
effectue une vérification de type à l'aide de RTTI . S'il échoue, il vous lancera une exception (si vous lui avez donné une référence) ou NULL si vous lui avez donné un pointeur.la source
Premièrement, pour décrire la conversion dynamique en termes C, nous devons représenter des classes en C. Les classes avec des fonctions virtuelles utilisent un "VTABLE" de pointeurs vers les fonctions virtuelles. Les commentaires sont en C ++. N'hésitez pas à reformater et corriger les erreurs de compilation ...
Ensuite, un casting dynamique est quelque chose comme:
la source
Il n'y a pas de classes en C, il est donc impossible d'écrire dynamic_cast dans ce langage. Les structures C n'ont pas de méthodes (par conséquent, elles n'ont pas de méthodes virtuelles), donc il n'y a rien de "dynamique" dedans.
la source
Non, pas facilement. Le compilateur attribue une identité unique à chaque classe, ces informations sont référencées par chaque instance d'objet, et c'est ce qui est inspecté au moment de l'exécution pour déterminer si une distribution dynamique est légale. Vous pouvez créer une classe de base standard avec ces informations et opérateurs pour effectuer l'inspection d'exécution sur cette classe de base, puis toute classe dérivée informerait la classe de base de sa place dans la hiérarchie des classes et toutes les instances de ces classes pourraient être castées à l'exécution via vos opérations.
Éditer
Voici une implémentation qui illustre une technique. Je ne prétends pas que le compilateur utilise quelque chose comme ça, mais je pense que cela démontre les concepts:
la source
dynamic_cast utilise RTTI. Cela peut ralentir votre application, vous pouvez utiliser la modification du modèle de conception des visiteurs pour obtenir un downcasting sans RTTI http://arturx64.github.io/programming-world/2016/02/06/lazy-visitor.html
la source
static_cast< Type* >(ptr)
static_cast en C ++ peut être utilisé dans des scénarios où tout le cast de type peut être vérifié au moment de la compilation .
dynamic_cast< Type* >(ptr)
dynamic_cast en C ++ peut être utilisé pour effectuer une conversion descendante sécurisée de type . dynamic_cast est le polymorphisme à l'exécution. L'opérateur dynamic_cast, qui convertit en toute sécurité d'un pointeur (ou référence) à un type de base en un pointeur (ou une référence) à un type dérivé.
par exemple 1:
Pour plus d'informations cliquez ici
par exemple 2:
la source