请问异常处理可不可以实现多态?怎么做?


新人第一次提问,有不妥之处请各位老师见谅!

我先从Except里派生了Except1和Except2:

   
  #ifndef EXCEPT_H
  
#define EXCEPT_H

class Except{
public:
Except(){}
virtual ~Except(){}

virtual const char* what() const{
return "Ex!";
}
};

class Except1: public Except{
public:
Except1(){}
virtual ~Except1(){}

virtual const char* what() const{
return "Ex1!";
}
};

class Except2: public Except{
public:
Except2(){}
virtual ~Except2(){}

virtual const char* what() const{
return "Ex2!";
}
};

#endif

然后thro类抛出异常:

   
  #ifndef THRO_H
  
#define THRO_H
#include "Except.h"
#include <iostream>
using std::cout;

class Thro{
public:
Thro(int a){
if(a==1)
throw &Except1();
else if(a==2)
throw &Except2();
cout<<"Fine.\n";
}
virtual ~Thro(){}
private:
int a;
};
#endif

主函数:

   
  #include <iostream>
  
#include "Except.h"
#include "thro.h"
using namespace std;

int main(){
int a;
try{
while(cin>>a){
Thro exp(a);
}
}catch(Except *ex){
cout<<ex->what()<<endl;
}
}

我自己臆想我分别把Except1、Except2的地址throw给了Except *ex,又因为what()是个virtual函数,所以他们应该分别调用Except1的what()和Except2的what(),但是经测试无论输入1或2,输出都是"Ex!"即基类的what(),请问哪里错了?应该怎么对异常处理实现多态?
多谢指教!

补充:我摸索了一下,抛出时这样做:

   
  Except1 *ex1=new Except1();
  
throw ex1;

就会得到我想要的效果。

C++ 异常处理

银二的恩特 12 years, 7 months ago

这是一个不是问题的问题,简单的说,犯了一个简单的错误,throw &Except1();,这里构造了一个局部对象,在栈上,返回的时候,这个对象已经被销毁了,换成throw (new Except1);这种方式就不会出现你所谓的问题,也不存在“异常处理可不可以实现多态”这种奇怪的题目。

稍微延伸一点说,为什么会输出"Ex!"。在throw &Except1();的时候,这个对象的续表指针指向的是Except1的虚表,假设该续表地址0x455004,其中的what方法的地址假设为0x455110,指向的是Except1的what方法,如果在这里直接调用该对象的what方法输出的一定是"EX1!",实现多态。当返回该对象的指针到cout<<ex->what()<<endl;的时候,这个对象已经不存在了,只是指向的存储没有被使用而已,其中的续表地址不再是Except1的0x455004,而是Except的虚表地址,执行的自然是Except的what方法。

虚表是由编译器产生,链接器初始化的,非对象相关,这里析构函数和构造函数所做的只是使虚表指针指向正确的位置,所以局部对象销毁之后,将会改写续表指针的指向,析构的时候是先子类后父类,父类析构的时候也会首先重置虚表指针,所以即使对象销毁了,你还可以看到调用了父对象的what方法。

信鸟你滴邪 answered 12 years, 7 months ago

Your Answer