c++之面向对象编程

概述

在面向对象程序(OOP)设计思想出现之前,程序采用面向过程的设计方法,程序由数据和函数组成,函数是程序的基本组成单元。面向过程方法灵活性强,逻辑简单,但函数名众多容易造成混乱,且函数和数据分开存放,联系不够紧密,在大型软件开发中采用面向过程方式效率低下、维护困难。

类和对象

类和对象是面向对象编程的核心,类和对象类似建筑图纸和大楼的关系,类是对象的一种抽象,对象是类的一个实例。在面向对象世界中,一切事物都可以用对象表示,对象间通过消息进行交流,无需了解对象的内部实现,只要知道各个对象提供的功能接口就能实现各种高级功能。

#include "stdafx.h"

#include <iostream>

using namespace std;

class Rect { //矩形类

private : //私有成员变量

int x1, y1, x2, y2;

public : //公共的

Rect(int leftTop[],int rightBottom[]) { //构造函数1,参数为左下角,右下角坐标数组

x1 = leftTop[0];

y1 = leftTop[1];

x2 = rightBottom[0];

y2 = rightBottom[1];

}

Rect(int _x1,int _y1,int width,int height) { //构造函数2,参数为左上角,宽度,高度

x1 = _x1;

y1 = _y1;

x2 = _x1 + width;

y2 = _y1 + height;

}

int Area();

};

 

int Rect::Area(){ //类体外实现操作

return abs(x2-x1)*abs(x2-y1); //宽乘以高(取绝对值)

}

 

int main()

{

 

int leftTop[] = {12,15};

int rightBottom[] = { 30,60 };

Rect r1(leftTop,rightBottom);

Rect r2(12,15,17,60);

cout<< "r1 面积:" << r1.Area()<<endl;

cout << "r2 面积:" << r2.Area() << endl;

return 0;

}

类和对象的关系

类是一种自定义数据类型,类似于C中的结构体(struct),不同之处在于类中包括数据和函数,而结构体只有数据。类是对象的形式上的抽象,不是一个实际存在的事物,它规定有哪些数据成员,哪些成员函数及具体功能,是对具体事物的一种描述。对象是类的实现(implement),对象根据类的描述信息生成一个真实的事物,占用实际内存,对象生成时要调用类的构造函数(construct)进行初始化(initialize),对象释放(Release)时要调用类的析构函数做必要的清理工作。

定义类

使用class关键字定义一个类,可在类中添加成员变量(member variable)和函数。一般在类里声明函数,在类外实现函数以体现类的封装性,也可以声明和实现都在类中完成,适用于简短且频繁调用的成员函数。通过类名调用函数使用作用域解析操作符::,如A::Calc(); ,通过对象名调用函数使用圆点操作符.,如a.Calc(); 。

构造函数

类不同于C++的基本数据类型,类的结构可能非常复杂,包括大量的成员变量和函数,仅仅简单的分配一块足够大小的内存给类对象是不够的,还需要对类中的成员变量进行集中初始化。C++提供构造函数来完成类对象的初始化操作,构造函数先根据类的大小分配一块足够的内存用于存放类对象,再根据构造函数传入的参数和具体实现完成类对象的初始化。

析构函数

类在释放自身之前可能需要做一些清理工作,如类在使用过程中动态分配了内存空间,在类释放之前需要手动释放这些内存。析构函数用于完成类释放之前的一些清理工作,由C++自动调用。

同构造函数,析构函数名为在类名前加~符号,如~Rect(),析构函数没有返回值也没有参数列表,每个类只有一个析构函数,若没有添加析构函数,C++提供默认的析构函数,但什么也不做。

 

#include "stdafx.h"

#include <iostream>

#include <string.h>

using namespace std;

class STR { //自定义的处理字符串类

private:

char* pValue; // 字符指针,指向字符串

int nCount; //字符串长度,不包括末尾的’\0’

public:

STR(const char* str) { //构造函数

nCount = strlen(str); //获取传入字符串的长度

pValue = new char[nCount + 1]; //根据长度分配相应大小的内存

strcpy_s(pValue, nCount + 1,str); //将传入字符串的值复制到类成员变量中

cout << "动态创建字符数组" << endl;

}

~STR() //析构函数

{

delete [] pValue; //释放动态创建的字符数组

pValue = NULL; //字符指针值设为0

cout<<"动态创建的字符数组被释放" <<endl;

}

char getValue(int nIndex){ //获取单个字符值

if (nIndex<0 || nIndex>=nCount) { //若索引参数超出了范围,返回’\0’

return '\0';

}

else

{

return pValue[nIndex]; //返回字符值

}

}

};

 

int main() {

const char* c;

c = "hello the world";

STR s1(c);

cout<<" 第6个字符:" << s1.getValue(5) <<endl;

cout << "第20个字符:" << s1.getValue(19) << endl;

return 0;

}

 

 

 

内联函数

程序代码中经常要调用函数,从调用点进入到函数的内部,执行完毕后返回调用点,函数调用需要一定的开销。C语言为节省函数调用带来的开销,常使用宏(macro)的方式模拟函数,如求和运算定义宏 #define SUM(a,b) (a+b) ,编译时用宏替换代码,减少函数调用的开销。

#include <iostream>

using namespace std;

class AB

{

private:

int a;

int b;

public:

inline int GetA(); // inline关键字声明为内联函数

int GetB(){ return b; } //函数在类内实现,默认为内联函数

void SetA(int _a){ a=_a; } //设置a的值

void SetB(int _b){ b=_b; } //设置b的值

};

int AB::GetA(){ //内联函数,返回a

return a;

}

int main()

{

AB ab;

ab.SetA(100);

ab.SetB(45);

cout<<"a="<<ab.GetA()<<endl; //内联函数,调用时直接将函数代码插入到该位置

cout<<"b="<<ab.GetB()<<endl;

return 0;

}

 

 

 

extern:

extern int eVar; //表明该变量已在其他文件中定义过

extern void eFun(); //表明该函数已定义过

//extern void sFun(); //静态函数,只在函数定义所在的文件中可用

int main()

{

eFun(); //调用外部定义的函数

return 0;

}

 

 

static成员

static(静态)关键字在不同场合具有不同的意义,也是常混淆用途的一个关键字(keyword)。在C语言中,static有两层含义,若在函数外用static修饰全局变量和函数,表示具有文件作用域,只能在本文件中可用,不能在其他文件中使用。

#include <iostream>

using namespace std;

void display() //自定义函数

{

static int num=1; //静态局部变量,永久存在

for(int i=1;i<=num;i++) //输出1到num间的值

cout<<i<<" ";

cout<<endl;

num++; //静态局部变量递增

}

int main()

{

display(); //第1次调用,num为1

display(); //第2次调用,num为2

display(); //第3次调用,num为3

return 0;

}

 

------------------------------------------------------------------------------------------------------------------

class STA

{

public:

static int a; //静态成员变量,所有对象使用同一个值

};

int STA::a = 0; //静态成员在类体外初始化

int main()

{

STA s1, s2, s3; //创建类对象

s1.a = 1; //设置变量值

cout << "s2.a " << s2.a << endl; //查看值

cout << "s3.a " << s3.a << endl; //查看值

return 0;

}

const成员

const(constant常量)修饰符用于表示一个变量在初始化后不能再被修改,即只读(read only)。const变量在定义时必须同时进行初始化,常用在函数参数中,表示该参数在函数内部不会被修改。

在传递类对象时,若采用传值方式,将类对象的拷贝传入函数,在类对象复杂的时候效率很低,一般传递类对象的引用,但若使用引用方式,类对象的值可能会被函数修改,这时使用const修饰符可限定类对象的值为只读,如GetLength(const CString& str)。

#include "stdafx.h"

#include <iostream>

#include <string.h>

using namespace std;

class Constant

{

public:

const int a; //const成员变量

int b;

Constant(int _a, int _b) :a(_a) { //构造函数,const成员要用初始化列表

b = _b; //非const成员初始化

}

int Sum() const { //const成员函数,不能修改成员变量值

return a + b;

}

void SetB(const int _b) { //const参数在函数体内不能被修改

this->b = _b;

}

};

 

int main()

{

Constant c1(20, 30); //创建对象并初始化

c1.SetB(50); //非const对象调用非const成员函数

cout << "非const对象:" << c1.Sum() << endl; //非const对象调用const成员函数

const Constant c2(20, 30); //const对象

cout << "const对象: " << c2.Sum() << endl; //const对象只能调用const成员函数

return 0;

}

 

 

友元

类的私有成员一般情况下在类外不可访问,但有时候需要在类外访问,可使用friend关键字,在被访问类中声明为friend的类或函数可以访问其私有成员。

使用friend修饰的类、函数称为友元类、友元函数,友元不是类的成员,但能像类成员函数一样访问类的私有成员,当需要同时访问多个类的私有成员,适宜使用友元。

#include "stdafx.h"

#include <iostream>

#include <string.h>

using namespace std;

class Equal; //友元类,在定义前使用需要做类声明

class FRI1

{

private:

int a; //私有成员

public:

friend class Equal; //类Equal是友元类,可以访问FRI1类的私有成员

FRI1(int _a) :a(_a) {} //构造函数

};

class FRI2

{

private:

int a;

public:

friend class Equal; //类Equal是友元类,可以访问FRI2类的私有成员

FRI2(int _a) :a(_a) {}

};

class Equal

{

public: //静态函数,可直接用类名调用,比较两个类的值是否相等

static bool equal(const FRI1& f1, const FRI2& f2) {

if (f1.a == f2.a) //若FRI1类对象的私有成员a等于FRI2类对象的私有成员

return true; //返回true

else

return false;

}

};

int main()

{

FRI1 f1(20);

FRI2 f2(20);

cout << "f1和f2的值是否相等:" << Equal::equal(f1, f2) << endl;

return 0;

}

 

运算符重载

C++提供一些运算符用于完成基本的运算,如+可以计算两个整型或浮点类型数值的和,==可以判断两个值是否相等,但都只能用于预置的基本类型。若想用+得到两个字符串拼接后的新字符串,用==判断两个类是否包含相同的值,可使用C++提供的运算符重载功能,类似函数重载,运算符可看做函数名,运算符两边的变量可看做函数的参数,调用时根据运算符的参数数目和类型自动选择匹配的版本。

了解运算符重载

运算符重载在定义时使用operator关键字,根据运算符操作数的数目分为一元重载和二元重载,如+、/、%为二元运算符,++、--为一元运算符,-当做减号为二元,当做负号为一元。

运算符可看做为函数,如operator +类似Add(STR a,int b); +两边的操作数类似参数a、b,重载的运算符可作为类的成员,也可作为类的友元函数,也可作为普通函数。

#include "stdafx.h"

#include <iostream>

using namespace std;

 

class IntOper

{

private:

int a; //私有成员

public:

void SetA(int _a) { //设置a的值

a = _a;

}

int GetA() { //获取a的值

return a;

}

int operator ++() { //默认为前缀,先自增,后赋值

a = a + 1;

return a;

}

int operator ++(int) { //添加int参数,表示后缀,先赋值,后自增

a = a + 1;

return a - 1;

}

int operator --() { //默认为前缀,先自减,后赋值

a = a - 1;

return a;

}

int operator --(int) { //添加int参数,表示后缀,先赋值,后自减

a = a - 1;

return a + 1;

}

};

int main()

{

IntOper oper;

oper.SetA(20); //设置值

cout << "oper : " << oper.GetA() << endl; //获取当前值

cout << "++oper : " << ++oper << endl; //前缀自增

cout << "oper++ : " << oper++ << endl; //后缀自增

cout << "--oper : " << --oper << endl; //前缀自减

cout << "oper-- : " << oper-- << endl; //后缀自减

 

return 0;

}

一元重载

一元重载只有一个操作数即类名,一般作为类成员,常用的一元运算符有自增、自减、求负运算符,其中自增、自减运算有前后之分,运算符在前表示先自增自减,然后再赋值,在后表示先赋值然后再自增自减,若为单独的表达式则没有区别。默认重载++、--为前缀版本,若表示后缀版本,添加一个int参数。

 

class IntArray

{

private:

int* pInt; //整型指针,指向动态创建的数组

int nCount; //元素数目

public:

IntArray(int count){ //构造函数,根据传入参数创建相应大小的数组

nCount=count;

pInt=new int[nCount];

}

~IntArray(){ //析构函数,释放动态创建的数组

delete [] pInt;

pInt=NULL;

}

int operator[](int index) const{ //重载[],参数为下标索引

if(index<0 || index>=nCount) //若参数不合理,返回0

return 0;

return pInt[index]; //返回对应位置的元素值

}

void SetAt(int index,int value){ //设置元素值,参数为索引和元素值

if(index<0 || index>=nCount) //若索引不合理,直接返回

return;

pInt[index]=value; //设置对应位置的元素值

}

int GetLength(){ //获取元素数目

return nCount;

}

};

 

int main()

{

IntArray arr(3); //创建对象,元素数目为3

arr.SetAt(0,12); //设置每个元素值

arr.SetAt(1,45);

arr.SetAt(2,80);

for(int i=0;i<arr.GetLength();i++) //输出所有元素

{

cout<<"第"<<i+1<<"个元素:"<<arr[i]<<endl; //调用重载的[]运算符,返回第i个元素值

}

cout<<endl;

return 0;

}

 

 

 

二元重载

二元重载有两个操作数,若作为类成员,只需一个参数,否则需要两个参数。参数的顺序代表操作数的位置,如operator +(A a,int b){} 调用形式为a+2; 不能为2+a; 若调换位置也可用,要再重载一次如operator +(int b,A a){}

 

 

 

继承性

面向对象编程的一个重要特性是继承性,类之间可以有继承关系,通过从一个父类派生出子类,子类在拥有父类功能的基础上,添加新增的功能,无需从零开始构建整个类,只需要补充新增的功能即可。C++允许多重继承,即从多个父类派生出一个子类,子类拥有多个父类的功能,多重继承虽功能强大,却复杂难以理解,在C#、Java中已取消了多重继承,应避免使用。

MFC类库中绝大多数类都继承于CObject类,CObject类提供了基本的服务,如运行时(runtime)的类型判断、对象的序列化存储等,所有从CObject类继承的类自动具有这些功能。

 

类的继承

父类称为基类,从基类继承的子类称为派生类,在类定义时指定要继承的基类,派生类自动获取基类的成员变量和函数,但不会获取基类的构造函数和析构函数。

创建派生类对象时,首先要初始化基类,可在派生类的构造函数里调用基类的构造函数,若没有显示调用基类的构造函数,自动调用基类的默认无参数版本构造函数。

 

#include <iostream>

#include <string> //包含string类头文件

using namespace std;

 

class Person //基类

{

protected: //保护成员,派生类中可访问

int nYear; //年龄

string sex; //性别

string name; //名称

public:

Person(){} //无参构造函数

Person(int _year,string _sex,string _name){

nYear=_year; //有参构造函数,初始化成员变量

sex=_sex;

name=_name;

}

void display(){ //输出成员,基类版本

cout<<"姓名:"<<name<<endl;

cout<<"年龄:"<<nYear<<endl;

cout<<"性别:"<<sex<<endl;

}

};

 

class Student:public Person //派生类,公有继承于类Person

{

protected: //保护成员

string school; //学校

string number; //学号

public:

Student(int _year,string _sex,string _name,string _school,string _number)

:Person(_year,_sex,_name){ //调用基类的构造函数

school=_school; //初始化新增成员变量

number=_number;

}

void display() //输出所有成员,派生类版本,函数重定义

{

Person::display(); //调用基类版本函数

cout<<"学校:"<<school<<endl; //输出

cout<<"学号:"<<number<<endl;

}

};

 

int main()

{

Student s1(1985,"男","Luo","hpu","0216"); //创建类对象并初始化

s1.display(); //调用派生类版本输出函数

return 0;

}

 

 

 

访问控制

类继承有三种方式:公有(public)、保护(protected)、私有(private)继承。基类的私有成员无论何种继承方式,在派生类中都不可访问。

若为私有继承,基类的公有和保护成员在派生类中变为私有。若为保护继承,基类的公有和保护成员在派生类变为保护成员。若为公有继承,基类的公有成员和保护成员在派生类中保持不变,一般情况下只使用public公有继承方式

 

 

调用流程

基类的构造函数和析构函数不会被派生类继承。若类B继承类A,类C继承类B,则创建一个类C对象时,先调用类A的构造函数,然后类B,再调用类C的构造函数,若类C对象释放时,先调用类C的析构函数,然后类B,最后调用类A的析构函数。即构造函数调用顺序为从基类到派生类,析构函数与构造函数顺序相反,从派生类到基类。

 

#include <iostream>

using namespace std;

 

class A //类A

{

public:

A(){ //构造函数

cout<<"构造 A"<<endl;

}

~A(){ //析构函数

cout<<"析构 A"<<endl;

}

};

class B:public A //类B派生自类A

{

public:

B(){

cout<<" 构造 B"<<endl;

}

~B(){

cout<<" 析构 B"<<endl;

}

};

class C:public B //类C派生自类B

{

public:

C(){

cout<<" 构造 C"<<endl;

}

~C(){

cout<<" 析构 C"<<endl;

}

};

 

int main()

{

C c1; //类C对象,创建时调用构造函数,释放时调用析构函数

return 0;

}

 

 

多态性

用类指针去调用类成员函数时,根据指针的类型即可确定调用的函数版本。如类B继承类A,类B重定义了类A的Calc函数,若有类A指针p调用Calc函数,调用了类A版本的Calc函数,若将类A指针p改为指向类B对象(指针类型没有变),再调用Calc函数,仍调用类A版本的Calc函数。重定义函数的调用仅与指针类型相关,与指针实际指向对象无关。

 

#include "stdafx.h"

#include <iostream>

#include <stdio.h>

#include <string.h>

using namespace std;

 

class A //基类

{

public:

virtual void Calc() { //使用virtual关键字,表明为虚函数

cout << "类A 版本的Calc" << endl;

}

};

class B :public A //派生类

{

public:

void Calc() { //重写虚函数

cout << "类B 版本的Calc" << endl;

}

};

int main()

{

A a; //类A对象

B b; //类B对象

A* p = &a; //类A指针,指向A对象

p->Calc(); //调用类A版本的Calc

p = &b; //指针改为指向类B对象

p->Calc(); //调用类B版本的Calc

return 0;

}

 

 

 

多态性的实现

多态性与函数重定义的区别在于:重定义函数的调用与指针类型相关,在程序编译时就确定了调用的函数版本,多态性的函数调用与指针实际所指对象相关,在程序运行时才确定调用的函数版本。

多态性通过一种晚期绑定的方式实现运行时的识别,实现晚期绑定可使用virtual关键字声明一个函数是虚函数,只需要在基类中声明函数为虚函数,在派生类中对该函数重写后,就可实现动态绑定。

 

 

 

virtual虚函数

添加一个virtual关键字就可以实现动态绑定,在于编译器为每个包含虚函数的类生成一个虚函数表(virtual table),同时在类对象的内存空间的头部添加一个虚指针,指向生成的虚函数表。虚函数表存放该类所有的虚函数,若在派生类中重写了基类的虚函数,则派生类的虚函数表中存放的是重写后的虚函数。

抽象类

在实际开发中,可能某些基类只是做个规范,形式上确定有哪些基本成员及其功能,并不涉及具体的实现。如基类CMap定义有虚函数Draw(),作为所有图形类的绘制函数,基类下有派生类CLine、CPoint、CRect分别用于绘制线、点、矩形,具体的图形绘制方法在派生类的Draw函数里完成,而基类的Draw只是一个接口的规范,不需要具体实现,此时可设置Draw函数为纯虚函数。

 

模板

标准C++库除了包含标准C函数库、IO输入输出类、string字符串类之外,还提供一套强大的通用类和算法库,即标准模板库STL(Standard Template Library),包括常见的数据结构和算法,如链表、栈、队列等。

得益于C++的模板(Template)机制,STL适用于任何数据类型,如链表list既可存放整型,也可存放string类型。模板也被称为泛型编程,忽略实际的数据类型,使用模板的函数和类可以适用于多种数据类型,从而节省工作量,提高代码重用性。

如何定义模板

在定义类或函数时使用模板可以忽略实际数据类型,调用时根据实际的数据类型,生成一个函数或类的具体定义。通过在函数或类的定义前添加template<class T>,表明定义的函数或类使用了模板机制,class是类型关键字,T是一个未知的数据类型,调用时被实际类型替换。若有两个模板参数,形式为template<class T1,class T2>,T1和T2为两个未知的数据类型。

#include "stdafx.h"

#include <iostream>

#include <stdio.h>

#include <string.h>

using namespace std;

 

template<class T> //模板声明,T为参数类型

T Sum(T a, T b) //模板函数,计算两个未知类型的和

{

return a + b;

}

 

int main()

{

int a = 10, b = 50;

double c = 15.2, d = 45.3;

char e = '0', f = '1';

cout << "int " << Sum(a, b) << endl; //整型参数

cout << "double " << Sum(c, d) << endl; //浮点型参数

cout << "char " << Sum(e, f) << endl; //字符型参数

return 0;

}

 

 

 

模板类

模板类是泛型程序设计的基础,可以处理多种类型的数据,将通用功能集成到模板类中,可节省大量重复性工作。类似于函数模板,定义模板类之前使用template<class T>做模板声明,在类中可用未知类型T进行相关处理。

template<class T>只能在其后的类或函数中使用一次,若要在多个类或函数中使用模板,需要各自在定义前声明一次。传入实际数据类型时,形式为Calc<int> c1(12,35); 在<>中输入数据类型。

 

template<class T> //模板声明

class Calc //模板类

{

private:

T a; //成员变量,未知类型

T b;

public:

Calc(T _a,T _b):a(_a),b(_b){} //构造函数

T Add(); //成员函数

T Sub();

};

template<class T> //模板函数

T Calc<T>::Add(){ //类外实现

return a+b;

}

template<class T>

T Calc<T>::Sub(){

return a-b;

}

int main()

{

Calc<int> c1(12,35); //模板类对象,指明对象类型为int

Calc<double> c2(35.8,15.3); //指明对象类型为double

cout<<"int "<<c1.Add()<<endl;

cout<<"double "<<c2.Sub()<<endl;

return 0;

}

 

 

 

标准模板库STL

STL是标准C++库的一部分,包含链表(list)、向量(vector)、栈(stack)、队列(queue)等常见数据结构,STL中的类都是模板类,适用于任意数据类型,也称为容器类。STL使用迭代器(iterator)遍历容器中的元素,迭代器类似于指针,根据迭代器变量可查找到容器中的某个元素。

通过迭代器重载的运算符可操作迭代器,如++用于将迭代器指向下一个元素,--用于指向上一个元素,==和!=用于判断两个迭代器是否指向同一个元素,*用于获取迭代器指向元素的引用。

向量:

#include <iostream>

#include <vector> //包含vector头文件

#include <string> //包含string头文件

using namespace std;

 

int main()

{

vector<string> v; //存放string类型的vector

v.push_back("1.Hello"); //尾部添加string字符串

v.push_back("2.Vector");

v.push_back("3.Test");

cout<<"元素数目:"<<v.size()<<endl; //元素数目

for(vector<string>::iterator p=v.begin();p!=v.end();p++) //使用迭代器遍历向量

cout<<*p<<endl; //获取迭代器指向的值

cout<<"第1个元素:"<<v[0]<<endl; //使用[]获取元素值

return 0;

}

链表(list)

#include <list> //包含list头文件

using namespace std;

 

int main()

{

list<int> ls; //存放int类型的list

cout << "所有元素: ";

for (int i = 1; i <= 10; i++) //添加10个元素

{

int value = rand() % 10; //获取0-9的随机值

ls.push_back(value); //添加到list尾部

cout << value << " "; //输出当前元素

}

cout << "排序后: "<< endl;

ls.sort(); //list排序,默认为升序

list<int>::iterator p; //当前类型的迭代器

for (p = ls.begin(); p != ls.end(); p++) //遍历list

cout << *p << " ";

cout << endl << "去除重复元素:";

ls.unique(); //list去除重复项

for (p = ls.begin(); p != ls.end(); p++)

cout << *p << " ";

cout << endl;

return 0;

}

 

 

异常处理

程序在执行过程中时常会发生一些异常(exception),如打开文件时找不到指定文件、分配内存时内存不足、除法运算中分母为0、连接不上数据库等,有些异常可通过代码判断,但有些是难以预测的。为保证程序运行时能够正确处理各种异常情况,不会直接崩溃退出,C++提供异常处理机制,可以获取运行时的异常情况,并提供错误处理方法,从而提高程序的健壮性。

处理程序异常

C++提供try和catch关键字处理异常情况,将正常执行的代码放入try{}语句块中,catch{}块中放入处理异常的代码。若无异常发生,只执行try块中的语句,若发生了异常,停止执行try块中剩下的语句,直接跳入catch块中执行异常处理代码,使用try和catch可以将正常代码和异常代码区分开来,增强代码的可读性。

double divide(double a,double b) //可抛出异常的函数

{

if(b==0) //若分母为0,抛出整型异常

throw 0;

return a/b;

}

int main()

{

double a=12.5;

double b=0;

double result;

try{ //异常处理

result=divide(a,b); //调用函数

cout<<"结果是"<<result;

}

catch(int e){ //捕获函数divide抛出的异常,参数类型与抛出类型一致

cout<<"分母不能为"<<e<<endl; //异常处理语句

}

return 0;

}

自定义异常类

throw可抛出任意类型的异常,可自定义一个异常类,用以提示更多的错误信息。MFC类库提供一系列异常类,用以抛出不同类型的异常,如内存不足抛出CMemoryException异常、文件错误抛出CFileException异常。

 

#include <iostream>

#include <string>

using namespace std;

 

class Exception //自定义异常类

{

private:

string message; //错误提示信息

public:

Exception(){ //构造函数

message="自定义的异常类";

}

string GetMessage(){ //获取错误信息

return message;

}

};

int main()

{

try{

int b=0;

if(b==0)

throw Exception(); //抛出自定义类异常

}

catch (Exception e){ //捕获抛出的自定义类异常

cout<<e.GetMessage()<<endl; //输出自定义类的错误信息

}

return 0;

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值