Sdílet prostřednictvím


dynamic_cast – operátor

Převede operand expression na objekt typu type-id.

dynamic_cast < type-id > ( expression )

Poznámky

type-id musí být ukazatel nebo odkaz na dříve definovaný typ třídy nebo "ukazatel na void".Typ expression musí být ukazatel, pokud je type-id ukazatel, nebo hodnota l, pokud je type-id odkaz.

Viz static_cast pro vysvětlení rozdílu mezi statickými a dynamickými převody přetypování a kdy je vhodné použít každého z nich.

Ve spravovaném kódu existují v chování dynamic_cast dvě rozbíjející změny:

  • dynamic_cast na ukazatele na nadřazený typ zabaleného výčtu selže za běhu, vrácením 0 místo převedeného ukazatele.

  • dynamic_cast již nevyvolá výjimku, pokud je type-id vnitřním ukazatelem na typ hodnoty s přetypováním, selhávajícím v době běhu. Přetypování nyní místo vyvolání vrátí hodnotu ukazatele 0.

Pokud je type-id ukazatel na jednoznačně přístupnou přímou nebo nepřímou základní třídu z expression, je výsledkem ukazatel na jedinečný podřízený objekt typu type-id.Příklad:

// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };

void f(D* pd) {
   C* pc = dynamic_cast<C*>(pd);   // ok: C is a direct base class
                                   // pc points to C subobject of pd 
   B* pb = dynamic_cast<B*>(pd);   // ok: B is an indirect base class
                                   // pb points to B subobject of pd
}

Tento druh převodu se nazývá "přetypování nahoru", protože přesunuje ukazatel v hierarchii tříd z odvozené třídy do třídy, ze které je odvozen.Přetypování nahoru je implicitní převod.

Pokud je type-id void*, provede se kontrola v době běhu pro určení skutečného typu expression.Výsledkem je ukazatel na celý objekt odkazovaný skrze expression.Příklad:

// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
   A* pa = new A;
   B* pb = new B;
   void* pv = dynamic_cast<void*>(pa);
   // pv now points to an object of type A

   pv = dynamic_cast<void*>(pb);
   // pv now points to an object of type B
}

Pokud není type-id void*, je provedena kontrola v době běhu pro zobrazení, zda může být objekt odkazovaný skrze expression převeden na typ odkazovaný skrze type-id.

Pokud je typ expression základní třída typu type-id, je provedena kontrola v době běhu pro zjištění, zda opravdu expression odkazuje na celý objekt typu type-id.Je-li tomu tak, je výsledkem ukazatel na celý objekt typu type-id.Příklad:

// dynamic_cast_3.cpp
// compile with: /c /GR
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
   B* pb = new D;   // unclear but ok
   B* pb2 = new B;

   D* pd = dynamic_cast<D*>(pb);   // ok: pb actually points to a D
   D* pd2 = dynamic_cast<D*>(pb2);   // pb2 points to a B not a D
}

Tento typ převodu se nazývá přetypování dolů, protože dochází k přesunu ukazatele hierarchie tříd od dané třídy do třídy, která je z něj odvozená.

V případě vícenásobné dědičnosti jsou zavedeny možnosti nejednoznačnosti.Zvažte hierarchii tříd zobrazenou na následujícím obrázku.

Pro typy CLR vede dynamic_cast buď k operaci no-op, v případě, že převod může být proveden implicitně, nebo k instrukci MSIL isinst, která provede dynamickou kontrolu a vrátí nullptr, pokud se převod nezdaří.

Následující příklad používá k určení, zda je třída instancí určitého typu, dynamic_cast:

// dynamic_cast_clr.cpp
// compile with: /clr
using namespace System;

void PrintObjectType( Object^o ) {
   if( dynamic_cast<String^>(o) )
      Console::WriteLine("Object is a String");
   else if( dynamic_cast<int^>(o) )
      Console::WriteLine("Object is an int");
}

int main() {
   Object^o1 = "hello";
   Object^o2 = 10;

   PrintObjectType(o1);
   PrintObjectType(o2);
}

Hierarchie třid znázorňující vícenásobnou dědičnost

Hierarchie třídy, který se zobrazuje více dědičnosti

Ukazatel na objekt typu D lze bezpečně přetypovat na B nebo na C.Avšak pokud je D přetypován na odkazování se na objekt A, která instance A bude výsledkem?Příklad může vést k chybě nejednoznačného přetypování.Tento problém lze vyřešit použitím dvou nejednoznačných přetypování.Příklad:

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
   D* pd = new D;
   B* pb = dynamic_cast<B*>(pd);   // first cast to B
   A* pa2 = dynamic_cast<A*>(pb);   // ok: unambiguous
}

Při použití virtuálních základních tříd by mohly být zavedeny další nejednoznačnosti.Zvažte hierarchii tříd zobrazenou na následujícím obrázku.

Hierarchie tříd znázorňující virtuální základní třídy.

Hierarchie třídy, který se zobrazuje virtuální základní třídy

V této hierarchii je A virtuální základní třída.Viz Virtuální základní třídy pro definici virtuální základní třídy.Při předání instance třídy E a ukazatele na podřízený objekt A, dynamic_cast na ukazatel B selže z důvodu nejednoznačnosti.Nejdříve je zapotřebí provést přetypování zpět na celý objekt E a následně se jednoznačným způsobem dostat zpět na vrchol hierarchie pro dosažení správného objektu B.

Zvažte hierarchii tříd zobrazenou na následujícím obrázku.

Hierarchie třídy znázorňující duplicitní základní třídy

Hierarchie třídy, který se zobrazuje duplicitní základní třídy

Předáním objektu typu E a ukazatele na podřízený objekt D pro přechod z podřízeného objektu D na objekt nejvíce vlevo A, se mohou provést tři převody..Je možné provést převod dynamic_cast z ukazatele D na ukazatel E, následně převod (buď dynamic_cast nebo implicitní převod) z E na Ba nakonec implicitní převod z ukazatele B na A.Příklad:

// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   E* pe = dynamic_cast<E*>(pd);
   B* pb = pe;   // upcast, implicit conversion
   A* pa = pb;   // upcast, implicit conversion
}

Operátor dynamic_cast lze také použít k vykonání "křížového přetypování". Pomocí stejné hierarchie tříd je možné přetypovat ukazatel, například z podřízeného objektu B na podřízený objekt D, pokud je celý objekt typu E.

Bereme-li v úvahu křížové přetypování, je možné provést převod z ukazatele D na ukazatel nejvíce vlevo A použitím pouze dvou kroků.Křížový odkaz lze přetypovat z D na B a následně implicitním přetypováním z B na A.Příklad:

// dynamic_cast_6.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   B* pb = dynamic_cast<B*>(pd);   // cross cast
   A* pa = pb;   // upcast, implicit conversion
}

Hodnota nulového ukazatele je převedena na hodnotu nulového ukazatele cílového typu použitím dynamic_cast.

Použitím dynamic_cast < type-id > ( expression ) a pokud expression nelze bezpečně převést na typ type-id, dojde z důvody kontroly v době běhu k selhání převodu.Příklad:

// dynamic_cast_7.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
   A* pa = new A;
   B* pb = dynamic_cast<B*>(pa);   // fails at runtime, not safe;
   // B not derived from A
}

Hodnota neúspěšného přetypování na typ ukazatele je nulový ukazatel.Neúspěšné přetypování na typ odkazu vyvolá výjimku bad_cast 82f1eehz(v=vs.120).md. Pokud expression necílí nebo neodkazuje na platný objekt, je vyvolána výjimka __non_rtti_object.

Viz typeid pro více informací o výjimce __non_rtti_object.

Příklad

Následující příklad vytvoří ukazatele základní třídy (struct A) na objekt (struct C). Toto a virtuální funkce umožňují polymorfismus modulu runtime.

Příklad také v hierarchii volá nevirtuální funkci.

// dynamic_cast_8.cpp
// compile with: /GR /EHsc
#include <stdio.h>
#include <iostream>

struct A {
    virtual void test() {
        printf_s("in A\n");
   }
};

struct B : A {
    virtual void test() {
        printf_s("in B\n");
    }

    void test2() {
        printf_s("test2 in B\n");
    }
};

struct C : B {
    virtual void test() {
        printf_s("in C\n");
    }

    void test2() {
        printf_s("test2 in C\n");
    }
};

void Globaltest(A& a) {
    try {
        C &c = dynamic_cast<C&>(a);
        printf_s("in GlobalTest\n");
    }
    catch(std::bad_cast) {
        printf_s("Can't cast to C\n");
    }
}

int main() {
    A *pa = new C;
    A *pa2 = new B;

    pa->test();

    B * pb = dynamic_cast<B *>(pa);
    if (pb)
        pb->test2();

    C * pc = dynamic_cast<C *>(pa2);
    if (pc)
        pc->test2();

    C ConStack;
    Globaltest(ConStack);

   // will fail because B knows nothing about C
    B BonStack;
    Globaltest(BonStack);
}
  

Viz také

Referenční dokumentace

Operátory přetypování

Klíčová slova jazyka C++