• C++之6|多态与异常


    六、多态与异常

    1、多态

    回顾例子24的继承,类A的是showx(),派生的类AX是showy(),是两个不同名函数。但实际中有时候会出现重名情况。比如基类A里的函数名叫show(),在派生类里自定义函数也叫show(),起了冲突。但,我们可以通过类来区分。

    例26、重名函数处理(多态1)

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
    	A(){ }
    	~A(){ }
    	void show()
    	{
    		cout<<"xxxxxxxxxxxxxxx"<<endl;
    	}
    };
    
    class AX:public A{
    public:
    	void show()
    	{
    		cout<<"yyyyyyyyyyyyyyy"<<endl;
    	}
    };
    
    int main()
    {
        A a;
        a.show();
        
    	AX b;
    	b.show();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ base1_3.cpp
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    xxxxxxxxxxxxxxx
    yyyyyyyyyyyyyyy
    @ubuntu:/mnt/hgfs/ub2$
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这个容易理解,然后有人就想尝试能不能只通过一种类声明一个对象,然后通过不同指针来区分基类跟派生类。

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
    	A(){ }
    	~A(){ }
    	void show()
    	{
    		cout<<"xxxxxxxxxxxxxxx"<<endl;
    	}
    };
    
    class AX:public A{
    public:
    	void show()
    	{
    		cout<<"yyyyyyyyyyyyyyy"<<endl;
    	}
    };
    
    int main()
    {
        //派生类的对象a
        AX a;
        AX *q = &a;
        A  *p = &a;
        
        //基类的对象b
        A b;
        AX *x = &b;
        A  *y = &b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    测试结果

    @ubuntu:/mnt/hgfs/ub2$ g++ base1_4.cpp
    base1_4.cpp: In function ‘int main()’:
    base1_4.cpp:32:13: error: invalid conversion from ‘A*’ to ‘AX*’ [-fpermissive]
         AX *x = &b;
                 ^~
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    说明:基类的指针可以指向派生类的对象,而派生类的指针是不能指向基类对象的

    于是,通过指针尝试打印show()

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
    	A(){ }
    	~A(){ }
    	void show()
    	{
    		cout<<"xxxxxxxxxxxxxxx"<<endl;
    	}
    };
    
    class AX:public A{
    public:
    	void show()
    	{
    		cout<<"yyyyyyyyyyyyyyy"<<endl;
    	}
    };
    
    int main()
    {
        AX a;
        AX *q = &a;
        A  *p = &a;
    	
        q->show();
        p->show();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ base1_5.cpp
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    yyyyyyyyyyyyyyy
    xxxxxxxxxxxxxxx
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    从而可以得出结论:指针访问成员的时候,主要由指针类型来决定,和指向的类无关

    案例中都是指向派生类对象a,但决定show()类型的是指针类型,p是基类A所以p的show()对应打印基类的x,跟派生类对象a的无关。

    现在有个特殊的需求,要求把基类的show()作为初始化,后续的派生类改动将对基类进行改动,这时就需要关键字:

    virtual		//修饰表示虚函数
        		//虚函数:基类指针可指向派生类对象,动态联编
    
    • 1
    • 2

    案例如下

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
    	A(){ }
    	~A(){ }
    	virtual void show()
    	{
    		cout<<"xxxxxxxxxxxxxxx"<<endl;
    	}
    };
    
    class AX:public A{
    public:
    	void show()
    	{
    		cout<<"yyyyyyyyyyyyyyy"<<endl;
    	}
    };
    
    int main()
    {
        AX a;
        AX *q = &a;
        A  *p = &a;
    	
        q->show();
        p->show();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ base1_6.cpp
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    yyyyyyyyyyyyyyy
    yyyyyyyyyyyyyyy
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这种情况下,就相当于和所指向对象的类有关,跟指针的类型无关

    像例中那样,虽然指针p是基类A的数据类型,但指向的a是派生类AX声明的对象,所以最终执行的是对象a的类型。

    例27、求周长长度和的函数

    要求该函数适用各种图形:圆、三角形、正方形,然后把三个图形周长相加。

    #include <iostream>
    
    using namespace std;
    
    class shape{
    public:
    	virtual double getC(void){
    
        }
    
    };
    
    class Cir:public shape{
    public:
    	Cir(double ri):r(ri) { }
    	double getC(void)
    	{
    		return 2*3.14*r;	
    	}
    private:
    	int r;
    };
    
    class Tri:public shape{
    public:
    	Tri(double a, double b, double c):e1(a),e2(b),e3(c){ }
    
    	double getC(void)
    	{
    		return e1+e2+e3;	
    	}
    private:
    	double e1;
    	double e2;
    	double e3;
    };
    
    class Rec: public shape{
    public:
    	Rec(double e)
    	{
    		this->e = e;
    	}
    	double getC(void)
    	{
    		return 4*e;	
    	}
    
    private:
    	double e;
    };
    
    double countC(shape *arr[], int n)
    {
    	double sum = 0;
    	for(int i=0; i<n; i++)
    	{
    		sum += arr[i]->getC();
    	}
    	
    	return sum;
    }
    
    int main()
    {
    	Cir c(1);
    	Rec r(3);
    	Cir c1(2);
    	Tri t(3,3,3);
    
    	shape *arr[] = {&c, &r, &c1, &t};
    
    	cout << "total C: "<<countC(arr, 4) << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    运行结果:

    @ubuntu:/mnt/hgfs/ub2$ g++ shape1.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    total C: 39.84
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4

    shape是基类,用于对各个图形的周长进行求和,而每个图形求和方式不一(三角形、圆、正方形),所以通过派生类的方式实现。以上处理形式就是多态。

    例中的虚函数没内容

    virtual double getC(void){
    
        }
    
    • 1
    • 2
    • 3

    可以写成纯虚函数

    virtual double getC(void) = 0;
    
    • 1

    写成纯虚函数的话可以避免直接拿类shape声明对象,比如

    #include <iostream>
    
    using namespace std;
    
    class shape{
    public:
    	virtual double getC(void){
    
        }
    
    };
    
    class Cir:public shape{
    public:
    	Cir(double ri):r(ri) { }
    	double getC(void)
    	{
    		return 2*3.14*r;	
    	}
    private:
    	int r;
    };
    
    class Tri:public shape{
    public:
    	Tri(double a, double b, double c):e1(a),e2(b),e3(c){ }
    
    	double getC(void)
    	{
    		return e1+e2+e3;	
    	}
    private:
    	double e1;
    	double e2;
    	double e3;
    };
    
    class Rec: public shape{
    public:
    	Rec(double e)
    	{
    		this->e = e;
    	}
    	double getC(void)
    	{
    		return 4*e;	
    	}
    
    private:
    	double e;
    };
    
    double countC(shape *arr[], int n)
    {
    	double sum = 0;
    	for(int i=0; i<n; i++)
    	{
    		sum += arr[i]->getC();
    	}
    	
    	return sum;
    }
    
    int main()
    {
        shape x;	//加这么一句,逻辑上说声明个图形对象(没交代是什么图形)
    	Cir c(1);
    	Rec r(3);
    	Cir c1(2);
    	Tri t(3,3,3);
    
    	shape *arr[] = {&c, &r, &c1, &t};
    
    	cout << "total C: "<<countC(arr, 4) << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ shape2.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    total C: 39.84
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4

    这种情况下声明了非法对象x却不会报错,而使用纯虚函数则可以对类shape进行限制,不能让其声明对象。

    如下

    #include <iostream>
    
    using namespace std;
    
    class shape{
    public:
    	virtual double getC(void) = 0;
    
    };
    
    class Cir:public shape{
    public:
    	Cir(double ri):r(ri) { }
    	double getC(void)
    	{
    		return 2*3.14*r;	
    	}
    private:
    	int r;
    };
    
    class Tri:public shape{
    public:
    	Tri(double a, double b, double c):e1(a),e2(b),e3(c){ }
    
    	double getC(void)
    	{
    		return e1+e2+e3;	
    	}
    private:
    	double e1;
    	double e2;
    	double e3;
    };
    
    class Rec: public shape{
    public:
    	Rec(double e)
    	{
    		this->e = e;
    	}
    	double getC(void)
    	{
    		return 4*e;	
    	}
    
    private:
    	double e;
    };
    
    double countC(shape *arr[], int n)
    {
    	double sum = 0;
    	for(int i=0; i<n; i++)
    	{
    		sum += arr[i]->getC();
    	}
    	
    	return sum;
    }
    
    int main()
    {
        shape x;	//加这么一句,逻辑上说声明个图形对象(没交代是什么图形)
    	Cir c(1);
    	Rec r(3);
    	Cir c1(2);
    	Tri t(3,3,3);
    
    	shape *arr[] = {&c, &r, &c1, &t};
    
    	cout << "total C: "<<countC(arr, 4) << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    运行结果能够有报错

    @ubuntu:/mnt/hgfs/ub2$ g++ shape3.cpp 
    shape3.cpp: In function ‘int main()’:
    shape3.cpp:64:11: error: cannot declare variable ‘x’ to be of abstract type ‘shape’
         shape x; //加这么一句,逻辑上说声明个图形对象(没交代是什么图形)
               ^
    shape3.cpp:5:7: note:   because the following virtual functions are pure within ‘shape’:
     class shape{
           ^~~~~
    shape3.cpp:7:17: note: 	virtual double shape::getC()
      virtual double getC(void) = 0;
                     ^~~~
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    例28、虚析构函数(基类指针释放派生类对象,内存泄漏)

    回顾例26,有个结论:基类的指针可以指向派生类的对象,而派生类的指针是不能指向基类对象的

    现在想了解派生类析构函数相关的内容,于是有

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
    	A(){ }
    	~A(){ cout<<"A~~~~~~~~~~~~"<<endl;}
    };
    
    class AX:public A{
    public:
    	~AX(){ cout<<"AX~~~~~~~~~~~~"<<endl;}
    };
    
    int main()
    {
        AX a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ base1_7.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    AX~~~~~~~~~~~~
    A~~~~~~~~~~~~
    @ubuntu:/mnt/hgfs/ub2$ 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    说明,派生类声明对象时,会先析构派生类,再析构基类。

    接下来是基类指针指向派生类然后释放指针

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
    	A(){ }
    	~A(){ cout<<"A~~~~~~~~~~~~"<<endl;}
    };
    
    class AX:public A{
    public:
    	~AX(){ cout<<"AX~~~~~~~~~~~~"<<endl;}
    };
    
    int main()
    {
        A *p = new AX;
        delete p;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ base1_8.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    A~~~~~~~~~~~~
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4

    发现这时候只会析构基类,如果想同时也能够析构派生类,则需要把基类析构函数声明成虚析构函数,如下

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
    	A(){ }
    	virtual ~A(){ cout<<"A~~~~~~~~~~~~"<<endl;}
    };
    
    class AX:public A{
    public:
    	~AX(){ cout<<"AX~~~~~~~~~~~~"<<endl;}
    };
    
    int main()
    {
        A *p = new AX;
        delete p;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ base1_9.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    AX~~~~~~~~~~~~
    A~~~~~~~~~~~~
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、异常

    例29、字符串转数字

    在很多开发情景下是需要字符串和数字间的转换,因为有时需要把数值转成字符串显示在屏幕上,有时需要把显示的字符串转成数值进行数据处理。

    先简单回顾一个转换函数

    atoi()
    
    • 1

    这是字符串转数值的函数,可以执行shell指令的man查看具体用法

    @ubuntu:/mnt/hgfs/ub2$ man atoi
    
    • 1

    先编个小例子

    #include <iostream>
    #include <stdlib.h>
    
    using namespace std;
    
    int main()
    {
        int data = atoi("1234");
        cout<< data << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ atoi1.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    1234
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4

    假如说传的不是1234而是abcd

    #include <iostream>
    #include <stdlib.h>
    
    using namespace std;
    
    int main()
    {
        int data = atoi("abcd");
        cout<< data << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ atoi2.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    0
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4

    说明输入字符串不是数的时候就会认定为非法(比如abcd),返回0。这里又存在一个问题:如果我转换的数是0的话,就不知道是非法情况还是没有非法。于是我们可以优化如下

    #include <iostream>
    #include <stdlib.h>
    #include <stdio.h>
    
    using namespace std;
    
    int myatoi(const char *str)
    {
        if(*str<'0' || *str>'9')
            printf("wrong arg!!\n");
        else
            return atoi(str);
    }
    
    int main()
    {
        int data = myatoi("abcd");
        cout<< data << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ atoi3.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    wrong arg!!
    12
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    发现打印信息有12,这个是执行**cout<< data << endl;**的结果,12表示printf打印内容的字符个数。

    有人会说能不能在执行printf后直接跳转,类似如下

    #include <iostream>
    #include <stdlib.h>
    #include <stdio.h>
    
    using namespace std;
    
    int myatoi(const char *str)
    {
        if(*str<'0' || *str>'9')
            printf("wrong arg!!\n");
        	goto XXX;
        else
            return atoi(str);
    }
    
    int main()
    {
        int data = myatoi("abcd");
        cout<< data << endl;
        
    XXX:
    	cout << "XXX" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    运行结果报错

    @ubuntu:/mnt/hgfs/ub2$ g++ atoi4.cpp 
    atoi4.cpp: In function ‘int myatoi(const char*)’:
    atoi4.cpp:12:5: error: ‘else’ without a previous ‘if’
         else
         ^~~~
    atoi4.cpp:11:11: error: label ‘XXX’ used but not defined
          goto XXX;
               ^~~
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这是因为goto不能跨函数使用。

    而在C++中是有方法解决这个问题的,即异常处理,使用关键字throwtrycatch

    #include <iostream>
    #include <stdlib.h>
    #include <stdio.h>
    
    using namespace std;
    
    int myatoi(const char *str)
    {
        if(*str<'0' || *str>'9')
        	throw "wrong arg!!";//抛给异常处理
        else
            return atoi(str);
    }
    
    int main()
    {
        try{
            int data = myatoi("abcd");
        	cout<< data << endl;
        }
        catch(const char *p)//异常处理
        {
            cout << p << endl;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ atoi5.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    wrong arg!!
    @ubuntu:/mnt/hgfs/ub2$
    
    • 1
    • 2
    • 3
    • 4

    在C++中已经对所抛的异常处理内容进行规范,纳在exception类中。

    #include <exception>
    
    • 1

    对上例进行规范,优化如下

    #include <iostream>
    #include <stdlib.h>
    #include <stdio.h>
    #include <exception>
    
    using namespace std;
    
    class myexception:public exception{
    public:
    	const char* what() const throw()
    	{
    		return "wrong arg!!";
    	}
    };
    
    int myatoi(const char *str)
    {
    	if(*str<'0' || *str>'9')
    		throw myexception();
    	else
    		return atoi(str);
    }
    
    int main()
    {
    
    	try{
    
    		int data = myatoi("asdfas");
    
    		cout<< data <<endl;
    	}
    	catch(myexception e)
    	{
    		cout<< e.what() <<endl;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    运行结果

    @ubuntu:/mnt/hgfs/ub2$ g++ atoi_exception.cpp 
    @ubuntu:/mnt/hgfs/ub2$ ./a.out
    wrong arg!!
    @ubuntu:/mnt/hgfs/ub2$ 
    
    • 1
    • 2
    • 3
    • 4

    使用exception的好处在于它对各种常见异常进行了规范,我们只需使用相应的处理函数即可,效率得以提高。以下是预定义异常类各种标准异常。
    在这里插入图片描述

  • 相关阅读:
    纽约联储测试CBDC以改善MogaFX外汇交易
    (附源码)springboot应用支撑平台和应用系统 毕业设计 984655
    【异常】理解Java中的异常处理机制
    常见自动化测试工具集合
    kubernetes之Pod控制器
    Linxu 【权限,粘滞位】
    解决Docker容器apt无法下载问题
    ROS常见问题 | 虚拟机打开RVIZ闪退出错
    Centos 7 磁盘分区及挂载 xfs
    3.容器的学习(1/2)
  • 原文地址:https://blog.csdn.net/weixin_44035986/article/details/125481505