异常处理
异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。
异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw。
throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
如果有一个块抛出一个异常,捕获异常的方法会使用 try 和 catch 关键字。try 块中放置可能抛出异常的代码,try 块中的代码被称为保护代码。使用 try/catch 语句的语法如下所示:
123456789101112try { // 保护代码}catch( ExceptionName e1 ) { //catch 块}catch( ExceptionName e2 ) { //catch 块}catch( Ex ...
C++模板
非常感激我队友大爹给的复习资料
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector 或 vector 。
您可以使用模板来定义函数和类,接下来让我们一起来看看如何使用。
函数模板
模板函数定义的一般形式如下所示:
template
ret-type func-name(parameter list) { // 函数的主体 }
在这里,type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。
下面是函数模板的实例,返回两个数中的最大值:
实例
1234567891011121314151617181920212223242526272829#include <iostream>#include <string> using namespace std; template <typename T>inl ...
多态-类型兼容(基类和派生类)
非常感激我队友大爹提供的复习资料
定义
类型兼容规则是指在需要基类对象的任何地方, 都可以使用公有派生类的对象来替代。
类型兼容规则中所指的替代包括以下的情况:
派生类的对象可以隐含转换为基类对象;
派生类的对象可以初始化基类的引用;
派生类的指针可以隐含转换为基类的指针;
在替代之后, 派生类对象就可以作为基类的对象使用, 但只能使用从基类继承的成员。
可以说, 类型兼容原则是多态性的重要基础之一。
示例1
1234class B{};class D : public B {};B b, *pb;D d;
此时:
派生类对象可以隐含转换为基类对象, 即用派生类对象中从基类继承来的成员逐个赋值给基类对象的成员; b=d;
派生类的对象也可以初始化基类对象的引用; B& rb = d;
派生类对象的地址也可以隐含转换为指向基类的指针; pb = &d;
示例2
1234567891011121314151617181920212223242526272829303132333435363738394041#inclu ...
多态-纯虚函数和抽象类
定义
在C++中, 可以将虚函数声明为纯虚函数, 格式为:
1virtual 返回值类型 函数名 (函数参数列表) = 0;
纯虚函数没有函数体, 只有函数声明, 在虚函数声明的结尾加上=0, 表明此函数为纯虚函数。最后的=0并不表示函数返回值为0, 它只起形式上的作用, 告诉编译系统"这是纯虚函数"。
包含纯虚函数的类成为抽象类(Abstract Class)。之所以说它抽象, 是因为它无法被实例化, 也就是无法创建对象。原因很明显, 纯虚函数没有函数体, 不是完整的函数, 无法调用, 也无法为其分配内存空间。
抽象类通常是作为基类, 让派生类去实现纯虚函数, 派生类必须实现纯虚函数才能被实例化;
抽象基类处理约束派生类的功能, 还可以实现多态;
一个纯虚函数就可以使类成为抽象基类, 但是抽象基类除了包含纯虚函数之外, 还可以包含其他的成员函数(虚函数或普通函数)和成员变量;
只有类中的虚函数才能被声明为纯虚函数, 普通成员函数和顶层函数均不能被声明为纯虚函数;
示例
继承关系:Line --> Rectangle --> Cuboid -- ...
多态-虚函数
非常感激我队友大爹给我的复习资料
虚函数的作用
允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
当把基类的某个成员函数声明为虚函数后,允许在其派生类中对该函数重新定义,赋予它新的功能,并且可以通过指向基类的指针指向同一类族中不同类的对象,从而调用其中的同名函数。由虚函数实现的动态多态性就是:同一类族中不同类的对象,对同一函数调用作出不同的响应。
有时在基类中定义的非虚函数会在派生类中被重新定义, 如果用基类指针调用该成员函数, 则系统会调用对象中基类部分的成员函数; 如果用派生类指针调用该成员函数, 则系统会调用派生类对象中的成员函数, 这并不是多态性行为(使用的是不同类型的指针), 没有用到虚函数的功能。
虚函数的使用方法
在基类用virtual声明成员函数为虚函数;这样就可以在派生类中重新定义此函数, 为它赋予新的功能, 并能被方便的调用。在类外定义虚函数时, 不必再加virtual;
在派生类中重新定义此函数, 要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同, 并根据派生类的需要重新定义函数体;
定 ...
多态-静态链接和动态链接
非常感激我队友大爹给我的复习资料
多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
示例
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <iostream>using namespace std;class Shape{ protected: int width; int height; public: Shape(int a=0, int b=0) : width(a), height(b) {} int area(){ cout << "Parent class area: " << endl; ...
多继承-构造函数和初始化
非常感激我队友大爹提供的复习资料
注意:
这里并没有列出全部基类和成员对象, 由于Base3类只有默认构造函数, 不需要给它传递参数,因此, Base3以及Base3类成员对象mem3就不必列出。
其次, 基类名和成员对象名的顺序是随意的。这个派生类构造函数的函数体为空, 可见实际上只是起到了传递参数和调用基类及内嵌对象的作用。
关于执行顺序
先调用基类的构造函数, 再调用内嵌对象的构造函数;
基类构造函数的调用顺序 : 按照派生类定义时的顺序; (2–> 1–> 3)
内嵌对象的调用顺序 : 按照成员在类中声明的顺序; (1–> 2–> 3)
示例
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778#include <bits/stdc++.h>using namespace std;c ...
派生类的构造函数和析构函数
基类的构造函数和析构函数不能被继承,基类成员的初始化只能在基类的构造函数中进行。
当创建一个派生类对象时,派生类的构造函数必须首先通过调用基类的构造函数来对基类的数据成员进行初始化,然后再执行派生类构造函数的函数体,对派生类新增的数据成员进行初始化。当派生类对象的生存期结束时,析构函数的调用顺序相反。
调用构造方式
隐式调用:不指定基类的构造函数,默认调用基类默认构造函数(不带参数或者带默认参数值的构造函数)
显式调用:指定调用基类的某个构造函数。除非基类有默认构造函数,否则都要用显示调用。
简而言之,如果基类有默认构造函数(包括两种情况:1. 不带形参表的构造函数;2. 带形参表,但是形参都有缺省值)的时候,派生类可以隐式调用这些构造函数,其他情况下,必须显式调用,指定基类的构造函数。
示例
隐式调用的情况
1234567891011121314151617181920212223242526272829303132333435363738394041#include <bits/stdc++.h>using namespace std;class A{ ...
多继承-虚继承
非常感激我队友大爹给我的复习资料
为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。在继承方式前面加上 virtual 关键字就是虚继承。
必须在虚派生的真实需求出现前就已经完成虚派生的操作。在示例中,当定义 D 类时才出现了对虚派生的需求,但是如果 B 类和 C 类不是从 A 类虚派生得到的,那么 D 类还是会保留 A 类的两份成员。换个角度讲,虚派生只影响从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。
示例
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253/*虚继承(Virtual Inheritance)为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。在继承方式前面加上 virtual 关键字就是虚继承 1. 必须在虚派生的真实需求出现前就已经完成虚派生的操作。在示例中,当定义 D 类时才出现了对虚 ...
多继承-菱形继承命名冲突
非常感激我队友大爹给我的复习资料
菱形继承
多继承(Multiple Inheritance)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个。
多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如典型的是菱形继承: A->B->D, A->C->D。
在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B–>D 这条路径,还是来自 A–>C–>D 这条路径。
示例
1234567891011121314151617181920212223242526272829303132333435363738394041 ...