dynamic_cast使用方式

 MSDN 里面有详细解答      

        c++提供了四种新的cast机制,分别为static_cast, const_cast, dynamic_castreinterpret_cast。虽然也支持c中使用一对圆括号来cast,但是由于c++c最大的区别是c++增加了类的概念,因此在子类与父类之间进行cast的时候,使用ccast方式是无法保证其正确性的,因此c++提供了新的cast机制(虽然比较丑陋而且需要敲打更多的code,但是提供了安全性):dynamic_cast

        对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。因此可以用来在运行期间进行类型判断。如下述演示代码。

   


class CShape...{...}
class CCircle:public CShape...{...}
class CRectangle: public CShape...{...}

CShape * pShape;
... 
//do something

if (dynamic_cast<CCircle * > (pShape))
...{
    
//process the Circle object
}
else if (dynamic_cast<CRectangle * > (pShape))
...{
    
//process the Rectangle object
}
else
...{
    
//error, just shape object
}

       如下面代码所示,将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理,即会作一定的判断。由于这会用到RTTI技术,因此需要启动运行时类型信息这一选项,而在VC.net 2003中默认是关闭的,所以需要人为的启动这一选项,如图1所示。否则编译器会报下面的警告:

warning C4541: “dynamic_cast”用在了带 /GR- 的多态类型“CBasic”上;可能导致不可预知的行为

从而导致程序在运行时发生异常。

但是dynamic_cast在将父类cast到子类时,父类必须要有虚函数。例如在图1中的代码中将CBasic类中的test函数不定义成virtual时,编译器会报错:

error C2683: dynamic_cast : “CBasic”不是多态类型

这是由于有了多态后,将子类对象赋值给父类对象才有意义。这样子类与父类之间的cast才有意义。

        当然如果使用dynamic_cast来直接将子类cast到父类(向上cast),那就无所谓了。即父类不需要一定有虚函数,也不需要开启运行时类型信息这一选项。


#include <iostream>
using namespace std;

class CBasic
...{
public:
     
virtual int test()...{return 0;}
};

class CDerived : public CBasic
...{
public:
    
virtual int test()...{    return 1;}
};

int main()
...{
    CBasic        cBasic;
    CDerived    cDerived;
    
    CBasic * pB1 = 
new CBasic;
    CBasic * pB2 = 
new CDerived;

//dynamic cast failed, so pD1 is null.
    CDerived * pD1 = dynamic_cast<CDerived * > (pB1);   
                
//dynamic cast succeeded, so pD2 points to  CDerived object                                        
    CDerived * pD2 = dynamic_cast<CDerived * > (pB2);   
    
//dynamci cast failed, so throw an exception.            
//    CDerived & rD1 = dynamic_cast<CDerived &> (*pB1);   

//dynamic cast succeeded, so rD2 references to CDerived object.
    CDerived & rD2 = dynamic_cast<CDerived &> (*pB2);   

    
return 0;
}

The expression dynamic_cast<type-id>( expression ) converts the operand expression to an object of type type-id. The type-id must be a pointer or a reference to a previously defined class type or a “pointer to void”. The type of expression must be a pointer if type-id is a pointer, or an l-value if type-id is a reference.

See static_cast for an explanation of the difference between static and dynamic casting conversions, and when it is appropriate to use each.

dynamic_cast < type-id > ( expression )

If type-id is a pointer to an unambiguous accessible direct or indirect base class of expression, a pointer to the unique subobject of type type-id is the result. For example:

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

  ...

}

This type of conversion is called an “upcast” because it moves a pointer up a class hierarchy, from a derived class to a class it is derived from. An upcast is an implicit conversion.

If type-id is void*, a run-time check is made to determine the actual type of expression. The result is a pointer to the complete object pointed to by expression. For example:

class A { ... };

 

class B { ... };

 

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

}

If type-id is not void*, a run-time check is made to see if the object pointed to by expression can be converted to the type pointed to by type-id.

If the type of expression is a base class of the type of type-id, a run-time check is made to see if expression actually points to a complete object of the type of type-id. If this is true, the result is a pointer to a complete object of the type of type-id. For example:

class B { ... };

class D : public B { ... };

 

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);  //error: pb2 points to a B, not a D

                        // pd2 == NULL

  ...

}

This type of conversion is called a “downcast” because it moves a pointer down a class hierarchy, from a given class to a class derived from it.

In cases of multiple inheritance, possibilities for ambiguity are introduced. Consider the class hierarchy shown in Figure 4.5.

Figure 4.5   Class Hierarchy Showing Multiple Inheritance

A pointer to an object of type D can be safely cast to B or C. However, if D is cast to point to an A object, which instance of A would result? This would result in an ambiguous casting error. To get around this problem, you can perform two unambiguous casts. For example:

void f()

{

  D* pd = new D;

  A* pa = dynamic_cast<A*>(pd);    // error: ambiguous

  B* pb = dynamic_cast<B*>(pd);    // first cast to B

  A* pa2 = dynamic_cast<A*>(pb);  // ok: unambiguous

}

Further ambiguities can be introduced when you use virtual base classes. Consider the class hierarchy shown in Figure 4.6.

Figure 4.6   Class Hierarchy Showing Virtual Base Classes

In this hierarchy, A is a virtual base class. See Virtual Base Classes for the definition of a virtual base class. Given an instance of class E and a pointer to the A subobject, a dynamic_cast to a pointer to B will fail due to ambiguity. You must first cast back to the complete E object, then work your way back up the hierarchy, in an unambiguous manner, to reach the correct B object.

Consider the class hierarchy shown in Figure 4.7.

Figure 4.7   Class Hierarchy Showing Duplicate Base Classes

Given an object of type E and a pointer to the D subobject, to navigate from the D subobject to the left-most A subobject, three conversions can be made. You can perform a dynamic_cast conversion from the D pointer to an E pointer, then a conversion (either dynamic_cast or an implicit conversion) from E to B, and finally an implicit conversion from B to A. For example:

void f(D* pd)

{

  E* pe = dynamic_cast<E*>(pd);

  B* pb = pe;    // upcast, implicit conversion

  A* pa = pb;    // upcast, implicit conversion

}

The dynamic_cast operator can also be used to perform a “cross cast.” Using the same class hierarchy, it is possible to cast a pointer, for example, from the B subobject to the D subobject, as long as the complete object is of type E.

Considering cross casts, it is actually possible to do the conversion from a pointer to D to a pointer to the left-most A subobject in just two steps. You can perform a cross cast from D to B, then an implicit conversion from B to A. For example:

void f(D* pd)

{

  B* pb = dynamic_cast<B*>(pd);    // cross cast

  A* pa = pb;            // upcast, implicit conversion

}

A null pointer value is converted to the null pointer value of the destination type by dynamic_cast.

When you use dynamic_cast < type-id > ( expression ), if expression cannot be safely converted to type type-id, the run-time check causes the cast to fail. For example:

class A { ... };

 

class B { ... };

 

void f()

{

  A* pa = new A;

  B* pb = dynamic_cast<B*>(pa);    // fails, not safe;

                        // B not derived from A

  ...

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值