C++中异常处理的小坑

C++中异常处理的小坑

小吐槽:不得不说,学习编程有一段时间了,C++是我所学过的语言中,最复杂最多坑的,但是为了成为一个合格的程序员,莫得办法咯。

前言提示:本文虽说是异常处理中的小坑,但其实本质上是多态和拷贝构造函数造成的。

1.异常处理

C++的异常处理和Java类似,都是采用:try{}catch{}throw三个关键字。而且try和catch是一对多的关系,为了能够及时捕获所有异常,C++中采用...为默认的捕获类型(类似于Java中的Exception类)。但是C++采用...的方式无法获取“异常值”(也就是Java中的Exception e的e变量)。

那么问题是是什么呢?当捕获异常时,我们常常会采用is-a的思想,例如Java中(由于学习C++没有几天,只能用熟悉点的Java做个比方了)各种异常均是Exception的一个子类,所以在无法确认异常类型时,往往采用Exception作为捕获类型。可是如果使用不当,C++会丢失多态的性质

2.栗子

为了进一步说明问题,可以手动定义一个Exception类和其子类IndexException。

Exception类

//
// Created by 张兴锐 on 2018/7/23.
//

#ifndef EXCEPTION_EXCEPTION_H
#define EXCEPTION_EXCEPTION_H


class Exception {


public:

    virtual ~Exception();

    Exception();


    virtual void printException();

};


#endif //EXCEPTION_EXCEPTION_H

注意,为实现多态,这里采用virtual关键字。

实现:

//
// Created by 张兴锐 on 2018/7/23.
//

#include "Exception.h"
#include <iostream>
using  namespace std;
Exception::~Exception() {
    cout<<"~Exception()"<<endl;
}

void Exception::printException() {
    cout<<"Exception print"<<endl;
}

Exception::Exception() {
    cout<<"Exception()"<<endl;
}

IndexException类

//
// Created by 张兴锐 on 2018/7/23.
//

#ifndef EXCEPTION_INDEXEXCEPTION_H
#define EXCEPTION_INDEXEXCEPTION_H


#include "Exception.h"

class IndexException : public Exception{
public:
    virtual void printException();

    IndexException();

    virtual ~IndexException();
};


#endif //EXCEPTION_INDEXEXCEPTION_H

同样的,为了实现多态,采用了virtual关键字。

实现

//
// Created by 张兴锐 on 2018/7/23.
//

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

void IndexException::printException() {
    cout<<"IndexException print"<<endl;
}

IndexException::~IndexException() {
    cout<<"~IndexException()"<<endl;
}

IndexException::IndexException() {
    cout<<"IndexException()"<<endl;
}

定义好了两个异常类,现在写个demo来测试一下:

#include <iostream>
#include "IndexException.h"
#include <string>
using namespace std;

void test(){
    throw IndexException();
}
int main() {
    try{
        test();
    }catch(Exception e){
        e.printException();
    }
    return 0;
}

按照多态的思想,这里e.printException();应该打印出IndexException的print,可是实际代码中却不是,打印结果如下:

Exception()
IndexException()
Exception print
~Exception()
~IndexException()
~Exception()

What the fuck!!

不过注意到多了一个析构函数的产生,显然这是为什么不能正确多态的原因,但是又没能调用Exception的构造函数,那么就剩下一个选择了–拷贝构造函数,加入拷贝构造函数的定义。

Exception(const Exception &exception);

Exception::Exception(const Exception &exception) {
    cout<<"Expcetion(const)"<<endl;
}

再Run一次:

Exception()
IndexException()
Expcetion(const)
Exception print
~Exception()
~IndexException()
~Exception()

完美!,正确解释了为什么没能正确多态。那么如何进行正确多态呢?其实这里可以利用C++的特性-引用进行正确多态:

   try{
        test();
    }catch(Exception &e){
        e.printException();
    }
    return 0;

运行结果:

Exception()
IndexException()
IndexException print
~IndexException()
~Exception()

3.总结

C++在函数调用,参数传递时,如果定义不当,会触发拷贝构造函数,相当于将原来的变量赋值了一份,这往往导致多态无法正确执行,如果要使多态正确执行,可以使用指针和引用

猜你喜欢

转载自blog.csdn.net/qq_35109096/article/details/81174198