请问异常处理可不可以实现多态?怎么做?
新人第一次提问,有不妥之处请各位老师见谅!
我先从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(),请问哪里错了?应该怎么对异常处理实现多态?
多谢指教!
补充:我摸索了一下,抛出时这样做:
就会得到我想要的效果。
Answers
这是一个不是问题的问题,简单的说,犯了一个简单的错误,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方法。