[C++] Ce face operatorul 'dynamic_cast'?

Despre limbajul de programare C++ si biblioteca standard STL (forum moderat)

[C++] Ce face operatorul 'dynamic_cast'?

Mesajde Ovidiu Cucu » 12 Aug 2011, 12:14

Intrebare
Ce face operatorul dynamic_cast?

Raspuns
Operatorul dynamic_cast<type>(expr) converteste tipul expresiei expr la (face cast la) tipul type, unde:
  • type este pointer sau referinta la un tip clasa sau pointer la void;
  • daca type este tip pointer, expr este pointer la un tip clasa;
  • daca type este tip referinta, expr este un tip clasa.
Exemplu [1]
Cod: Selectaţi tot
   CFoo foo;
   CBar rBar = dynamic_cast<CBar&>(foo);
   CBar* pBar = dynamic_cast<CBar*>(&foo);
   void* p = dynamic_cast<void*>(&foo);

Fata de alti operatori cast, dynamic_cast face verificari la run-time (in timpul executei programului).
Exceptand cazul in care type este void*, conversia este corecta daca cel mai derivat obiect din expr pointeaza (refera) la un sub-obiect public de tipul type in mod ne-ambiguu.
Un pic mai clar, in exemplele urmatoare:
Exemplu [2]
Cod: Selectaţi tot
class A {virtual void f() {}};

int main()
{
   A* pA = new A;
   void* p = dynamic_cast<void*>(pA); // OK, void* can point to anyting
   // ...
}

Exemplu [3]
Cod: Selectaţi tot
class A {virtual void f() {}};
class B : public A {};
class C : public A {};
class D : public B {};

int main()
{
   A* pA = new D;
   // most derived object pointed by pA is of type 'class D'
   // pA also unambiguously points to public sub-objects of
   // type 'class B' and type 'class A'.

   D* pD = dynamic_cast<D*>(pA); // run-time test succeeds
   B* pB = dynamic_cast<B*>(pA); // run-time test succeeds
   const A* pA2 = dynamic_cast<const A*>(pA); // run-time test succeeds
   // ...
}

Exemplu [4]
Cod: Selectaţi tot
class A {virtual void f() {}};
class B {virtual void f() {}};

int main()
{
   B b;

   // 'class A' and 'class B' are unrelated classes,
   // then 'b' does not refer to a sub-object of type 'class A'.
   A& rA = dynamic_cast<A&>(b); // run-time test fails 
   // ...
}

Exemplu [5]
Cod: Selectaţi tot
class A {virtual void f() {}};
class B : public A {};
class C : public A {};
class D : public B {};

int main()
{
   B* pB = new B;
 
   // pB does not point to a sub-object of type 'class C'.
   C* pC = dynamic_cast<C*>(pB); // run-time test fails 

   // pB does not point to a sub-object of type 'class D'.
   D* pD = dynamic_cast<D*>(pB); // run-time test fails 
   // ...
}

Exemplu [6]
Cod: Selectaţi tot
class A {virtual void f() {}};
class B : protected A {};

int main()
{
   B b;
   // b refers to a sub-object of type 'class A' which is not public.
   A& rA = dynamic_cast<A&>(b); // Inaccessible base; run-time test fails
   // ...
}

Exemplu [7]
Cod: Selectaţi tot
class A { virtual void f() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};

int main()
{
   D* pD = new D;

   // pD points to a public sub-object of type 'class A'
   // which is not unique because of multiple non-virtual inheritance.
   A* pA = dynamic_cast<A*>(pD); // Ambiguous base; run-time test fails
   // ...
}

Atunci cand testul esueaza...
  • ...daca s-a facut cast la un pointer, valoarea returnata este pointerul NULL;
    Exemplu [8]
    Cod: Selectaţi tot
       B* pB = dynamic_cast<B*>(pA);
       if(NULL == pB)
       {
          // run-time test failed
       }
  • ...daca s-a facut cast o referinta, atunci se arunca o exceptie tip bad_cast.
    Exemplu [9]
    Cod: Selectaţi tot
       try
       {
          A& rA = dynamic_cast<A&>(b);
       }
       catch(std::bad_cast& e)
       {
          // run-time test failed
          std::cout << e.what() << std::endl;
       }

Note
  1. Pentru ca operatorul dynamic_cast face verificari la run-time, se poate zice ca este inclus in mecanismul RTTI (Run-Time Type Identification).
    Exemplu [10]
    Cod: Selectaţi tot
    class A {virtual void f() = 0;};
    class B : public A {virtual void f() {}};
    class C : public A {virtual void f() {}};
    class D : public A {virtual void f() {}};

    void some_function(A* pA)
    {
       if(NULL == dynamic_cast<B*>(pA))
       {
          // pA points to a 'class B' object
       }
       else if(NULL == dynamic_cast<C*>(pA))
       {
          // pA points to a 'class C' object
       }
       else if(NULL == dynamic_cast<D*>(pA))
       {
          // pA points to a 'class D' object
       }
    }

  2. Pentru a putea face conversii intre clase folosind dynamic_cast, clasele trebuie sa fie polimorfice, adica sa contina functii virtuale. Alfel, compilatorul semnaleaza o eroare.
    Exemplu [11]
    Cod: Selectaţi tot
    class A {/* no virtual functions */};
    class B : public A {};

    int main()
    {
       A* pA = new B;
       B* pB = dynamic_cast<B*>(pA);
       // Compiler error. dynamic_cast: 'A' is not a polymorphic type
       // ...
    }
  3. Printre programatorii C++ si prin diverse manuale/tutoriale este raspandita afirmatia "dynamic_cast nu eşuează niciodată atunci când convertim o clasă în clasa de bază". Exemplele [6] si [7] dovedesc contrariul.
  4. Acest articol este "under construction" iar pe parcurs poate sa sufere modificari si adaugiri. Daca descoperiti greseli, omisiuni sau neclaritati, va rog sa deschideti un topic in forumul de discutii "Limbajul C++".
Resurse
Vezi si


<< Back to C++ Index
Avatar utilizator
Ovidiu Cucu
Fondator
Fondator
 
Mesaje: 3776
Membru din: 11 Iul 2007, 16:10
Localitate: Iasi
Judet: Iaşi

Înapoi la C++

Cine este conectat

Utilizatorii ce navighează pe acest forum: Niciun utilizator înregistrat şi 0 vizitatori

cron