C++学习笔记
课程链接
C++语言程序设计基础(2021春)
C++语言程序设计进阶(2021春)
第一章 绪论
-
C++支持的程序设计方法
- 面向过程的程序设计方法
- 面向对象的程序设计方法
面向过程:
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素
缺点:没有面向对象易维护、易复用、易扩展
面向对象:
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
缺点:性能比面向过程低 - 泛型程序设计方法(写的代码可以被很多不同类型的对象所重用,一般由继承实现)
-
C++程序的开发过程
- 算法设计
- 源程序编辑
- 编译
- 连接:连接目标程序以及库中的某些文件,生成可执行文件
- 运行调试
-
三种不同类型的翻译程序
- 汇编程序:将汇编语言源程序翻译成目标程序
- 编译程序:将高级语言源程序翻译成目标程序
- 解释程序:将高级语言源程序翻译成机器指令,边翻译边执行
第二章 C++简单程序设计
- 各基本类型的取值范围

-
符号常量
- 常量定义语句形式:
const 数据类型 常量名 = 常量值 - 符号常量定义时一定要初始化,在程序中间不能改变其值
- 常量定义语句形式:
-
逗号运算和逗号表达式
- 格式:表达式1,表达式2
- 求解顺序及结果:先求表达式1,再求表达式2,最终结果为表达式2的值
-
枚举类型
- 语法形式:
注意:整数值不能直接赋给枚举变量,要进行强制类型转换,枚举值可以赋给整型变量enum <枚举类型名> {变量值列表} // 例 enum Weekday{SUN, MON, TUE, WED, THU, FRI, SAT}; // 默认情况下:SUN=0,MON=1, ......, SAT=6 - 示例程序:
#include <iostream> using namespace std; enum GameResult {WIN, LOSE, TIE, CANCEL}; int main() { GameResult result; enum GameResult omit = CANCEL; for (int count = WIN; count <= CANCEL; count++) { result = GameResult(count); if (result == omit) cout << "The game was cancelled" << endl; else { cout << "The game was played "; if (result == WIN) cout << "and we won!"; if (result == LOSE) cout << "and we lost."; cout << endl; } } return 0; } /* 输出: The game was played and we won! The game was played and we lost. The game was played The game was cancelled */
- 语法形式:
-
auto 类型与 decltype类型
auto:编译器通过初始值自动判断变量的类型decltype:定义一个变量与某一表达式的类型相同,但并不用该表达式初始换变量// sum的类型就是函数f返回值的类型 decltype(f()) sum = x;- 为了解决复杂的类型声明而使用的关键字
- 可以作用于变量、表达式及函数名
第三章 函数
- 函数的参数传递
- 在函数调用时才分配形参的存储单元
- 值传递是单项传递,引用传递可实现双向传递
- 常引用作参数可以保障实参数据的安全
一般引用作形参:
- 不用作参数传递(实参赋值给形参),节省开销,提高效率。
- 函数可以改变形参的值
- 实参不能是常量
常引用作形参: - 不用作参数传递(实参赋值给形参),节省开销,提高效率。
- 函数不能改变形参的值
- 实参可以是常量
- 引用的概念
- 定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象
- 一旦一个引用被初始化后,就不能改为指向其他对象
- 含有可变参数的函数
initializer_listinitializer_list <变量类型> 变量名initializer_list是一个类模板- 其对象中的元素永远是常量值,无法改变元素的值
- 内联函数
- 在函数声明前加上关键字
incline - 编译时在调用出用函数体进行替换,节省了参数传递,控制转移等开销
- 内联函数体内不能有循环语句和
switch语句 - 内联函数的定义必须出现在内联函数第一次被调用之前
- 对内联函数不能进行异常接口声明
- 在函数声明前加上关键字
constexpr函数- 语法规定:
constexpr修饰的函数在其所有参数都是constexpr时,一定返回constexpr;- 函数体中必须有且只有一条
return语句
- 示例:
constexpr int get_size() {return 20;} constexpr int foo = get_size();
- 语法规定:
- 带默认参数值的函数
- 默认参数值的说明次序:有默认参数的形参必须列在形参列表的最右
- 默认参数值与函数的调用位置:若一个函数有原型声明,且原型声明在定义之前,则默认参数值应在函数原型声明中给出;若只有函数的定义,或函数定义在前,则默认参数值可以函数定义中给出
- 函数重载
- 功能相近的函数在相同的作用域内衣相同函数名声明
- 示例:
// 形参类型不同 int add(int x, int y); float add(float x, float y); // 形参个数不同 int add(int x, int y); int add(int x, int y, int z);
第四章 类与对象
- 如果紧跟在类名称的后面声明私有成员,则关键字
private可以省略 private类型与protect类型private修饰的成员变量只有类内可直接访问protect修饰的成员变量类内和子类均可直接访问
- 默认构造函数
- 调用时可以不需要实参的构造函数
- 参数表为空的构造函数
- 全部参数都有默认值的构造函数
- 示例:
// 下面两个函数若在类中同时出现将产生编译错误 Clock(); Clock(int newH = 0, int newM = 0, int newS = 0);
- 调用时可以不需要实参的构造函数
- 委托构造函数
- 类中往往有多个构造函数,只是参数表和初始化列表不同,其初始化算法都是相同的, 这时,为了避免代码重复,可以使用委托构造函数。
- 示例:
// 构造函数 Clock(int newH, int newM, int newS): hour(newH), minute(newM), second(newS){ } // 委托构造函数 Clock(): Clock(0, 0, 0) {}
- 复制构造函数
- 其形参为本类的对象引用
- 作用:用一个已存在的对象去初始化同类型的新对象
- 示例:
class 类名 { public : 类名(形参);//构造函数 类名(const 类名 &对象名);//复制构造函数 // ... }; 类名::类( const 类名 &对象名)//复制构造函数的实现 { 函数体 } - 复制构造函数被调用的情况
- 定义一个对象时,已本类另一个对象作为初始值,发生复制构造
- 若函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造
- 如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化一个临时无名对象传递给主调函数,此时发生复制构造
- 前向引用声明
- 若需要在某个类的声明之前引用该类,则应进行前向引用声明
- 在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象
- 当使用前向引用声明时,只能使用被声明的符号,而不能设计类的任何细节
- 示例:
// 正确示例 class B; //前向引用声明 class A { public: void f(B b); }; class B { public: void g(A a); }; //----------------------- // 错误示例 class Fred; //前向引用声明 class Barney { Fred x; //错误:类Fred的声明尚不完善 }; class Fred { Barney y; }; // 应改为: class Fred; //前向引用声明 class Barney { Fred *x; }; class Fred { Barney y; };
- 结构体与类
- 类的缺省访问权限时
private,结构体的缺省访问权限是public - 结构体主要用来保存数据、没有什么操作的类型
- 类的缺省访问权限时
- 联合体
- 特点:
- 成员共用同一组内存单元
- 任何两个成员不会同时有效
- 示例:
union Mark { //表示成绩的联合体 char grade; //等级制的成绩 bool pass; //只记是否通过课程的成绩 int percent; //百分制的成绩 };
- 特点:
- 枚举类
- 语法形式:
enum class 枚举类型名: 底层类型 {枚举值列表}; - 示例:
enum class Type { General, Light, Medium, Heavy}; enum class Type: char { General, Light, Medium, Heavy}; enum class Category { General=1, Pistol, MachineGun, Cannon}; - 常与
switch,case一同使用
- 语法形式:
第五章 数据的共享与保护
- 对象的生存期
- 静态生存期
- 与程序的运行期相同
- 在文件作用域中声明的对象具有这种生存期
- 在函数内部声明静态生存期对象,要用关键字
static
- 动态生存期
- 块作用域中声明的,没有用static修饰的对象是动态生存期的对象(习惯称局部生 存期对象)
- 开始于程序执行到声明点时,结束于命名该标识符的作用域结束处
- 静态生存期
- 类的静态数据成员
- 用关键字
static声明 - 为该类的所有对象共享
- 必须在类外定义和初始化,用(::)来指明所属的类
- 用关键字
- 类的静态函数成员
- 类外代码可以使用类名和作用域操作符来调用静态成员函数
- 静态成员函数主要用于处理该类的静态数据成员,可以直接调用静态成员函数
- 如果访问非静态成员,要通过对象来访问
- 类的友元
- 友元是C++提供的一种破坏数据封装和数据隐藏的机制
- 通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息
- 可以使用友元函数和友元类
- 友元函数
- 友元函数在它的函数体中能够通过对象名访问
private和protected成员 - 作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择
- 访问对象中的成员必须通过对象名
- 友元函数不是成员函数
- 友元函数在它的函数体中能够通过对象名访问
- 友元类
- 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员
- 类的友元关系是单向的,若声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据
- 示例:
class A { friend class B; public: void display() { cout << x << endl; } private: int x; }; class B { public: void set(int i); void display(); private: A a; }; void B::set(int i) { a.x=i; } void B::display() { a.display(); }
- 常类型
- 常对象:必须进行初始化,不能被更新
const 类名 对象名 - 常成员:用
const进行修饰的类成员:常数据成员和常函数成员- 常成员函数不更新对象的数据成员
- 常成员函数声明格式:
类型说明符 函数名(参数表)const;//在实现部分也要带const关键字 - 通过常对象只能调用它的常成员函数
- 常引用:被引用的对象不能被更新
const 类型说明符 &引用名 - 常数组:数组元素不能被更新
类型说明符 const 数组名[大小] - 常指针:指向常量的指针
- 常对象:必须进行初始化,不能被更新
- C++程序的一般组织结构
- 类声明文件(.h文件)
- 类实现文件(.cpp文件)
- 类的使用文件(main()所在的.cpp文件)
- 条件编译指令
-
#if 常量表达式1 程序正文1 //当“ 常量表达式1”非零时编译 #elif 常量表达式2 程序正文2 //当“ 常量表达式2”非零时编译 #else 程序正文3 //其他情况下编译 #endif -
#ifdef 标识符 程序段1 #else 程序段2 #endif // 如果“标识符”经#defined定义过,且未经undef删除,则编译程序段1;否则编译程序段2 -
#ifndef 标识符 程序段1 #else 程序段2 #endif // 如果“标识符”未被定义过,则编译程序段1;否则编译程序段2
-
第六章 数组、指针与字符串
- 整数0可以赋给指针,表示空指针
- 允许定义或声明指向
void类型的指针,该指针可以被赋予任何类型对象的地址 - C++11使用
nullptr关键字,是表达更准确,类型安全的空指针 - 指向常量的指针
- 不能通过指向常量的指针改变所指对象的值,但指针本身可以改变,可以指向其他的对象
- 指针类型的常量
- 若声明指针常量,则指针本身的值不能被改变
- 指针类型的函数
- 注意不要将非静态局部地址用作函数的返回值,例如:
int* function(){ int local=0; //非静态局部变量作用域和寿命都仅限于本函数体内 return &local; }//函数运行结束时,变量local被释放
- 注意不要将非静态局部地址用作函数的返回值,例如:
- 指向函数的指针
- 示例:
#include <iostream> using namespace std; int compute(int a, int b, int(*func)(int, int)) { return func(a, b);} int max(int a, int b) // 求最大值 { return ((a > b) ? a: b);} int min(int a, int b) // 求最小值 { return ((a < b) ? a: b);} int sum(int a, int b) // 求和 { return a + b;} int main(){ int a, b, res; cout << "请输入整数a:"; cin >> a; cout << "请输入整数b:"; cin >> b; res = compute(a, b, & max); cout << "Max of " << a << " and " << b << " is " << res << endl; res = compute(a, b, & min); cout << "Min of " << a << " and " << b << " is " << res << endl; res = compute(a, b, & sum); cout << "Sum of " << a << " and " << b << " is " << res << endl;}
- 示例:
- C++11 的智能指针
unique_ptr:不允许多个指针共享资源,可以用标准库中的move函数转移指针shared_ptr:多个指针共享资源weak_ptr:可复制shared_ptr,但其构造或者释放对资源不产生影响
- 移动构造
第七章 继承与派生
- 单继承时派生类的定义
class 派生类名:继承方式 基类名{ 成员声明;} - 多继承时派生类的定义
class 派生类名:继承方式1 基类名1,继承方式2 基类名2,...{ 成员声明; } // 注意:每一个“继承方式”,只用于限制对紧随其后之基类的继承 - 三种继承方式
- 公有继承
- 继承的访问控制
- 基类的
public和protected成员:访问属性在派生类中保持不变 - 基类的
private成员:不可直接访问
- 基类的
- 访问权限
- 派生类中的成员函数:可以直接访问基类中的
public和protected成员,但不能直接访问基类的private成员 - 通过派生类的对象:只能访问
public成员
- 派生类中的成员函数:可以直接访问基类中的
- 继承的访问控制
- 私有继承
- 继承的访问控制
- 基类的
public和protected成员:都以private身份出现在派生类中 - 基类的
private成员:不可直接访问
- 基类的
- 访问权限
- 派生类中的成员函数:可以直接访问基类中的
public和protected成员,但不能直接访问基类的private成员 - 通过派生类的对象:不能直接访问从基类继承的任何成员
- 派生类中的成员函数:可以直接访问基类中的
- 继承的访问控制
- 保护继承
- 继承的访问控制
- 基类的
public和protected成员:都以protected身份出现在派生类中 - 基类的
private成员:不可直接访问
- 基类的
- 访问权限
- 派生类中的成员函数:可以直接访问基类中的
public和protected成员,但不能直接访问基类的private成员 - 通过派生类的对象:不能直接访问从基类继承的任何成员
- 派生类中的成员函数:可以直接访问基类中的
- 继承的访问控制
- 公有继承
protected成员的特点与作用- 对建立其所在类对象的模块来说,它与
private成员的性质相同 - 对于其派生类来说,它与
public成员的性质相同 - 既实现了数据隐藏,又方便继承,实现代码重用
- 对建立其所在类对象的模块来说,它与
- 类型转换
- 公有派生类对象可以被当作基类的对象使用,反之则不可
- 派生类的对象可以隐含转换为基类对象
- 派生类的对象可以初始化基类的引用
- 派生类的指针可以隐含转换为基类的指针
- 通过基类对象名、指针只能使用从基类继承的成员
- 公有派生类对象可以被当作基类的对象使用,反之则不可
- 派生类的构造函数
- 单继承时构造函数的定义语法
派生类名::派生类名(基类所需的形参,本类成员所需的形参): 基类名(参数表), 本类成员初始化列表{ //其他初始化; }; - 多继承时构造函数的定义语法
派生类名::派生类名(参数表) : 基类名1(基类1初始化参数表), 基类名2(基类2初始化参数表), ... 基类名n(基类n初始化参数表), 本类成员初始化列表 { //其他初始化; };
- 单继承时构造函数的定义语法
- 构造函数的执行顺序
- 调用基类构造函数
- 顺序按照它们被继承时声明的顺序(从左向右)
- 对初始化列表中的成员进行初始化
- 顺序按照它们在类中定义的顺序
- 对象成员初始化时自动调用其所属类的构造函数。由初始化列表提供参数
- 执行派生类的构造函数体中的内容
- 调用基类构造函数
- 访问从基类继承的成员
- 作用域限定
- 当派生类与基类中有相同成员时:
- 若未特别限定,则通过派生类对象使用的是派生类中的同名成员
- 如要通过派生类对象访问基类中被隐藏的同名成员,应使用基类名和作用域操作符 (::)来限定
- 当派生类与基类中有相同成员时:
- 二义性问题
- 如果从不同基类继承了同名成员,但是在派生类中没有定义同名成员,“派生类对 象名或引用名.成员名”、“派生类指针->成员名”访问成员存在二义性问题
- 解决方式:用类名限定
- 作用域限定
- 虚基类
- 需要解决的问题
- 当派生类从多个基类派生,而这些基类又共同基类,则在访问此共同基类中 的成员时,将产生冗余,并有可能因冗余带来不一致性
- 虚基类声明
- 以
virtual说明基类继承方式 - 例:
class B1:virtual public B
- 以
- 作用
- 主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题
- 为最远的派生类提供唯一的基类成员,而不重复产生多次复制
- 注意:在第一级继承时就要将共同基类设计为虚基类
- 示例:
#include <iostream> using namespace std; class Base0 { public: int var0; void fun0() { cout << "Member of Base0" << endl; } }; class Base1: virtual public Base0 { public: int var1; }; class Base2: virtual public Base0 { public: int var2; }; class Derived: public Base1, public Base2 { //定义派生类Derived public: int var; void fun() { cout << "Member of Derived" << endl; } }; int main() { Derived d; d.var0 = 2; //直接访问虚基类的数据成员 d.fun0(); //直接访问虚基类的函数成员 return 0; }
- 需要解决的问题
第八章 多态性
- 运算符重载为成员函数
- 重载为类成员的运算符函数定义形式
函数类型 operator 运算符(形参){ ......}// 参数个数=原操作数个数-1 (后置++、--除外) - 双目运算符重载规则
- 如果要重载 B 为类成员函数,使之能够实现表达式
oprd1 B oprd2,其中oprd1为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是oprd2所属的类 型 - 经重载后,表达式
oprd1 B oprd2相当于oprd1.operator B(oprd2)
- 如果要重载 B 为类成员函数,使之能够实现表达式
- 前置单目运算符重载规则
- 如果要重载
U为类成员函数,使之能够实现表达式U oprd,其中oprd为A类对 象,则U应被重载为 A 类的成员函数,无形参 - 经重载后, 表达式
U oprd相当于oprd.operator U()
- 如果要重载
- 后置单目运算符 ++和--重载规则
- 如果要重载
++或--为类成员函数,使之能够实现表达式oprd++或oprd--,其 中oprd为A类对象,则++或--应被重载为 A 类的成员函数,且具有一个int类 型形参 - 经重载后,表达式
oprd++相当于oprd.operator ++(0)
- 如果要重载
- 示例:(++i与i++区别原理)
class Clock {//时钟类定义 public: Clock(int hour = 0, int minute = 0, int second = 0); void showTime() const; //前置单目运算符重载 Clock& operator ++ (); //后置单目运算符重载 Clock operator ++ (int); private: int hour, minute, second; }; Clock::Clock(int hour, int minute, int second) { if (0 <= hour && hour < 24 && 0 <= minute && minute < 60 && 0 <= second && second < 60) { this->hour = hour; this->minute = minute; this->second = second; } else cout << "Time error!" << endl; } void Clock::showTime() const { //显示时间 cout << hour << ":" << minute << ":" << second << endl; } Clock & Clock::operator ++ () { second++; if (second >= 60) { second -= 60; minute++; if (minute >= 60) { minute -= 60; hour = (hour + 1) % 24; } } return *this; } Clock Clock::operator ++ (int) { //注意形参表中的整型参数 Clock old = *this; ++(*this); //调用前置“++”运算符 return old; }
- 重载为类成员的运算符函数定义形式
- 运算符重载为非成员函数
- 运算符重载为非成员函数的规则
- 双目运算符 B重载后, 表达式
oprd1 B oprd2等同于operator B(oprd1, oprd2) - 前置单目运算符 B重载后, 表达式
B oprd等同于operator B(oprd ) - 后置单目运算符
++和--重载后, 表达式oprd B等同于operator B(oprd, 0)
- 双目运算符 B重载后, 表达式
- 示例:
class Complex { public: Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { } friend Complex operator+(const Complex &c1, const Complex &c2); friend Complex operator-(const Complex &c1, const Complex &c2); friend ostream & operator<<(ostream &out, const Complex &c); private: double real; //复数实部 double imag; //复数虚部 }; Complex operator+(const Complex &c1, const Complex &c2){ return Complex(c1.real+c2.real, c1.imag+c2.imag); } Complex operator-(const Complex &c1, const Complex &c2){ return Complex(c1.real-c2.real, c1.imag-c2.imag); } ostream & operator<<(ostream &out, const Complex &c){ out << "(" << c.real << ", " << c.imag << ")"; return out; }
- 运算符重载为非成员函数的规则
- 虚函数
- 虚函数时实现运行时多态性基础
- 构造函数不能时虚函数,析构函数可以是虚函数
- 虚函数的声明:
virtual 函数类型 函数名(形参表); - 虚函数声明只能出现在类定义中的函数原型声明中,而不能在成员函数实现的时候
- 在派生类中可以对基类中的成员函数进行覆盖
- 派生类可以不显式地用
virtual声明虚函数,系统判断条件为:- 该函数是否与基类的虚函数有相同的名称、参数个数及对应参数类型
- 该函数是否与基类的虚函数有相同的返回值或者满足类型兼容规则的指针、 引用型的返回值
- 若派生类从名称、参数及返回值三个方面满足上述条件就会自动确定为虚函数
- 虚析构函数使用场景:
- 可能通过基类指针删除派生类对象
- 如果你打算允许其他人通过基类指针调用对象的析构函数(通过
delete这样做是正 常的),就需要让基类的析构函数成为虚函数,否则执行delete的结果是不确定的
- 虚表
- 每个多态类有一个虚表,其中有当前类的各个虚函数的入口地址
- 虚表示意图

- 抽象类
- 纯虚函数
- 纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定义具体的操作内容, 要求各派生类根据实际需要定义自己的版本
- 纯虚函数的声明格式为:
virtual 函数类型 函数名(参数表) = 0;
- 抽象类
- 带有纯虚函数的类称为抽象类:
class 类名{ virtual 类型 函数名(参数表)=0; //其他成员……}
- 带有纯虚函数的类称为抽象类:
- 注意:
- 抽象类只能作为基类来使用
- 不能定义抽象类的对象
- 纯虚函数
- C++11:
override与finaloverride- 多态行为的基础:基类声明虚函数,继承类声明一个函数覆盖该虚函数
- 覆盖要求: 函数签名(函数名、参数列表、
const)完全一致
final- 用来避免类被继承,或是基类的函数被改写
- 示例:
struct Base1 final { }; struct Derived1 : Base1 { }; // 编译错误:Base1为final,不允许被继承
第九章 模板与群体数据
- 函数模板定义语法
- 语法形式:
template <模板参数表>函数定义 - 模板参数表的内容
- 类型参数:
class(或typename)标识符 - 常量参数:类型说明符 标识符
- 模板参数:
template <参数表> class 标识符
- 类型参数:
- 语法形式:
- 类模板
- 类模板的声明:
- 类模板:
template <模板参数表>class 类名 {类成员声明}; - 若需要在类模板以外定义其成员函数,则要采用以下的形式:
template <模板参数表>类型名 类名<模板参数标识符列表>::函数名(参数表)
- 类模板:
- 类模板的声明:
第十章 泛型程序设计与C++标准模板库
- 泛型程序设计的基本概念
- 编写不依赖于具体数据类型的程序
- 将算法从特定的数据结构中抽象出来,成为通用的
- C++的模板为泛型程序设计奠定了关键的基础
- STL的基本组件
- 容器(container)
- 基本容器类模板
- 顺序容器
- array(数组)、vector(向量)、deque(双端队列)、forward_list(单链表)、list(列表)
- (有序)关联容器
- set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)
- 无序关联容器
- unordered_set (无序集合)、unordered_multiset(无序多重集合)
- unordered_map(无序映射)、unorder_multimap(无序多重映射)
- 顺序容器
- 容器适配器 :stack(栈)、queue(队列)、priority_queue(优先队列)
- 基本容器类模板
- 迭代器
- 函数对象
- 算法
- 容器(container)
第十一章 流类库与输入/输出
第十二章 异常处理
- 异常处理的语法
- 示例:
#include <iostream> using namespace std; int divide(int x, int y) { if (y == 0) throw x; return x / y; } int main() { try { cout << "5 / 2 = " << divide(5, 2) << endl; cout << "8 / 0 = " << divide(8, 0) << endl; cout << "7 / 1 = " << divide(7, 1) << endl; } catch (int e) { cout << e << " is divided by zero!" << endl; } cout << "That is ok." << endl; return 0; } // 输出 5 / 2 = 28 is divided by zero! That is ok. - 自动析构
- 找到到一个匹配的
catch异常处理后- 初始化异常参数
- 将从对应的
try块开始到异常被抛掷处之间构造(且尚未析构)的所有自动 对象进行析构 - 从最后一个
catch处理之后开始恢复执行
- 找到到一个匹配的
- C++标准库各种异常类所代表的异常
