dynamic_cast和polymorphic_cast的比较

C++中的多态转换是通过函数dynamic_cast来实现的。
适用于dynamic_cast函数的典型场合有两种:从基类向派生类的向下转型和交叉转型(crosscast),即从一个基类到另一个基类的转型。为了理解这两个概念的含义,参考下面的代码,可以将polymorphic_cast换成dynamic_cast。
类型继承关系,在base1和base2中,分别有一个虚析构函数(delete p的时候方便?因为p是一个基类指针,而它要释放的是子类对象?):

  1. class base1
  2. {
  3. public:
  4.     virtual ~base1() {}
  5. };
  6. class base2
  7. {
  8. public:
  9.     virtual ~base2() {}
  10. };
  11. class derived : public base1,public base2 /*这个public如果少掉的话,就不能交叉转型(polymorphic_cast抛出异常);汗,这么个错误,害我找了半天!*/
  12. {
  13. };

例子代码:

  1. base1* p1 = new derived; 
  2. derived* pD = boost::polymorphic_cast<derived*>(p1); //从基类向派生类的向下转型
  3. pD->only_here();//此函数仅在derived中可用
  4. pD->only_base2();//derived的非虚函数,在基类base2中也有一个同名的非虚函数
  5. //我们如何调用基类的同名非虚函数呢?像下面这样转换一下就可以了。
  6. base2* pB=boost::polymorphic_cast<base2*>(p1);//交叉转型,以获得基类base2的指针
  7. pB->only_base2();

所谓的“交叉”,yathing是这样理解的:p1是一个base1的指针,但它实际指向的是derived对象,现在将它转化为base2的指针,正是一种“基类到基类”的交叉——当然!derived对象是“安全转换”的关键,这个子类对象是可以调用其基类对象的(安全)。但是,假设你想将一个base1对象,转换为一个base2对象,恐怕任何cast操作都帮不上忙!(简直异想天开)

引申思考:在子类对象中调用基类的同名隐藏函数,还有没有其它的实现方式?

dynamic_cast注意事项:
开启RTTI选项,在VC6、VC2003下,默认是关闭的。

dynamic_cast的缺点:
The C++ Programming Laguage 3rd Edition . Stroustrup:“由于疏忽,有时可能会忘了测试指针是否为空——这种情况肯定时有发生。如果您担心这点的话,那么您可以编写一个转换函数,以便在转换操作失败时抛出异常。”
在Boost中,提供的polymorphic_cast正是这样一个转换函数。

dynamic_cast和polymorphic_cast的对比:
polymorphic_cast比dynamic_cast优秀的地方,就是它们两者的区别:无论什么情况下,只要所执行的函数dynamic_cast包含了指针,就必须测试所返回的指针是否为空。如果认为指针为空是错误的,那么就应该抛出一个bad_cast异常。而对于polymorphic_cast来说,错误处理局限在std::bad_cast的异常处理中(指针为空,它也会抛出bad_cast异常),这就意味着不需要为转型的返回值的测试担心了——减少了代码工作量和出错的概率。
对比下面的代码:

  1. void polymorphic_cast_example(base1* p)
  2. {
  3.  derived* pD=boost::polymorphic_cast<derived*>(p);
  4. }
  5. void dynamic_cast_example(base1* p)
  6. {
  7.  derived *pD=dynamic_cast<derived*>(p);
  8.  if(!pD) //多了这么个容易被遗漏的检查!
  9.   throw std::bad_cast();
  10. }
  11. int main()
  12. {
  13.  base1* p=new derived;
  14.  try
  15.  {
  16.   polymorphic_cast_example(p);
  17.   dynamic_cast_example(p);
  18.  }
  19.  catch(std::bad_cast & e)
  20.  {
  21.   std::cout<<e.what()<<'/n';
  22.  }
  23.  delete p;
  24. }

关于dynamic_cast缺点的示例:

 

  1. #include <boost/cast.hpp>  
  2. #include <iostream>  
  3. using namespace std;
  4. using namespace boost;
  5. class base1
  6. {
  7.     virtual ~base1(){}
  8. };
  9. class base2
  10. {
  11. public:
  12.     void ba2_fun()
  13.     {
  14.         cout<<"base2_fun"<<endl;
  15.     }
  16. };
  17. class derived : public base1,base2
  18. {
  19. public:
  20.     void de_fun()
  21.     {
  22.         cout<<"de_fun"<<endl;
  23.     }
  24. };
  25. int main()
  26. {
  27.     base1* p = new derived;  //change this with "base1* p = NULL;"程序仍然可以运行!这就是问题! 
  28.     dynamic_cast<derived*>(p)->de_fun();//base1 must have a virtual function  
  29.     base2* pD = dynamic_cast<base2*>(p);
  30.     pD->ba2_fun();
  31.     return 0;
  32. }

明白了吧?在对象根本不存在的情况下,怎么能够允许函数得到调用呢?势必给我们的程序造成隐患。

那么polymorphic_cast又如何呢?尝试下面的代码:

  1. base1* p = NULL;
  2. polymorphic_cast<derived*>(p)->de_fun();

结果如何?程序抛出异常,终止!这就是好处了!它会提醒你:p还没被初始化呢!当然,正确的写法,还是应该使用try...catch语句。

 

总结一下,使用polymorphic_cast和dynamic_cast这两个函数的时机:

1,当预期会出现多态转型失败时,使用dynamic_cast<T*>函数,它可以清楚地表明转型失败不是错误。

2,当多态转型必须成功以确保逻辑的正确性时,使用polymorphic_cast<T*>函数,它可以清楚地表明转型失败是一种错误。

3,当对引用类型执行多态转型时,使用dynamic_cast函数。

你可能感兴趣的:(c,工作,测试,null,delete,fun)