第十九章 19.2.1节练习

练习19.3

已知存在如下的类继承体系,其中每个类分别定义了一个公有的默认构造函数和一个虚析构函数:

class A{/* ... */};

class B : public A{/*...*/};

class C : public B{/*...*/};

class D : public B, public A{/*...*/};

下面的哪个dynamic_cast将失败?

(a) A *pa = new C;

      B *pb = dynamic_cast< B* >(pa);

(b) B *pb = new B;

      C *pc = dynamic_cast< C* >(pb);

(c) A *pa = new D;

      B *pb = dynamic_cast< B* >(pa);

解答:

感谢asjdhs同学的提醒(详见评论),之前的代码的确有一些问题。

这里需要注意的是”注意转换指针的时候不会抛异常,只有在转引用的时候才会抛异常“。

更新如下:

测试代码如下:

#include <iostream>

using namespace std;

class A{
public:
	A() = default;
	virtual ~A(){}
};

class B : public A{
public:
	B() = default;
	virtual ~B(){}
};

class C : public B{
public:
	C() = default;
	virtual ~C(){}
};

class D : public B, public A{
public:
	D() = default;
	virtual ~D(){}
};

#define choose 1

int main(){
#if choose == 1
  A *pa = new C;
  B *pb = dynamic_cast<B*>(pa);
  cout << "a's result: pb's address is " << static_cast<void*>(pb) << endl;
#elif choose == 2
  B *pb = new B;
  C *pc = dynamic_cast<C*>(pb);
  cout << "b's result: pc's address is " << static_cast<void*>(pc) << endl;
#else
  A *pa = new D;
  B *pb = dynamic_cast<B*>(pa);
  cout << "c's result: pb's address is " << static_cast<void*>(pb) << endl;
#endif
}

这里我们将编译器换为clang3.4。
这里使用宏choose的原因是为了分开不同的小题(因为不同的题会在runtime和compiling-time有问题)

a) 当choose为1时,转换是没有问题的,你会在终端或命令行窗口中看到指针指向的地址。

b) 当choose为2时,转换就会出问题了,这个时候你会在命令行或终端窗口中看到指针指向的地址为0。这是C++在运行时对类型的检查。

    这里原因可以参见MSDN(https://msdn.microsoft.com/en-us/library/cby9kycs.aspx)的 dynamic_cast_3.cpp上的解释。

c) 当choose为其他值时,编译都会出问题。我们来看看clang和gcc给出的错误信息:

clang3.4

test.cc:42:11: error: ambiguous conversion from derived class 'D' to base class 'A':
    class D -> class B -> class A
    class D -> class A
  A *pa = new D;
          ^~~~~
1 error generated.

gcc4.9.2

test.cc:42:15: error: ‘A’ is an ambiguous base of ‘D’
   A *pa = new D;
               ^

这里gcc的提示很简练,clang的提示很丰富。要表达的意思都是一个,因为这里使用到了多重继承,所以这里转换有二义性。

这里有疑问的是从那种继承方式往A进行转换(如同clang给出的提示那样)。

MSDN(上面网址)的 dynamic_cast_5.cpp上的解释,大家可以参考。


练习19.4

使用上一个练习定义的类改写下面的代码,将表达式*pa转换成类型C&:

if(C *pc = dynamic_cast< C* >(pa)){

  // 使用C的成员

} else {

  // 使用A的成员

}

解答:

我的理解如下:

int main(){
	A *pa = new C;
	try{
		C &pc = dynamic_cast<C&>(*pa);
	}
	catch (bad_cast &e){
		cout << e.what() << endl;
	}
}

练习19.5

在什么情况下你应该使用dynamic_cast替代虚函数?

解答:

【引用】我们想使用基类对象指针或引用执行某个派生类操作并且该操作不是虚函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值