继承
- 1. 继承的概念及定义
- 1.1 概念
- 1.2 继承定义
- 1.2.1 格式
- 1.2.2 继承基类成员访问方式的变化
- 2. 基类和派生类对象赋值转换
- 3. 继承中的作用域
- 4. 派生类的默认成员函数
- 5. 继承与友元
- 6. 继承与静态成员
- 7. 菱形继承
- 7.1 单继承
- 7.2 多继承
- 7.3 菱形继承
- 7.4 虚拟继承virtual
1. 继承的概念及定义
1.1 概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类,称基类,特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
1.2 继承定义
class ATS
{
public:void Print(){cout << "ATS" << endl;}protected:int _A;string _T;vector<double> _S;
};class ats :public ATS
{
public:void Print(){cout << "ats" << endl;}private:int _a;string _t;vector<double> _s;
};
1.2.1 格式
1.2.2 继承基类成员访问方式的变化
根据继承方式和访问限定符的种类,会产生9种结果,总结下来:
归纳:
- 基类的private成员在派生类中始终不可见。这里的不可见指的是派生类不能使用,而不是没有该成员。
- 基类成员在派生类中的访问方式可以根据 Min(成员在基类的访问限定符,继承方式)判断。其中public>protected>private
- 使用class关键字时默认是private,struct关键字时默认是public。在这里还是推荐显示写出继承方式。
- 实际中一般都写public继承
2. 基类和派生类对象赋值转换
- 派生类对象可以给基类对象/基类指针/基类引用赋值
- 基类对象不能给派生类对象赋值
- 基类指针/引用可以通过强制类型转换给派生类指针/引用赋值
3. 继承中的作用域
- 每个类都有其自己的作用域
- 子类继承了父类的成员函数后,此时会存在两个同名函数,这两个函数会构成隐藏关系,而不是重载。如果想要调用父类的成员函数只需要加上显示访问。
- 写的时候避免出现同名函数
4. 派生类的默认成员函数
继承后的子类也会有其默认成员函数。
- 派生类的构造函数,基类部分初始化时必须调用基类的默认构造函数。如果没有默认构造函数则需要显示调用。
- 同理,派生类的**拷贝构造和operator=**也必须调用基类的部分完成对基类的初始化。
- 关于析构函数。派生类会在调用完其析构函数后自动调用基类的析构函数来完成对基类部分的析构。保证基类在派生类之后析构。
- 在初始化时,先基类后派生类
- 在析构时,先派生类后基类
- 析构函数需要构成重写,除非基类中使用virtual
5. 继承与友元
无论是父类/子类,其友元都不是对方的友元。
6. 继承与静态成员
当父类定义了一个static成员,则整个继承体系内只有这一个成员,无论多少个子类,都只有一个static成员实例。
7. 菱形继承
7.1 单继承
一个子类只有一个直接父类时称这个继承关系为单继承
7.2 多继承
一个子类有两个或以上直接父类时称这个继承关系为多继承
7.3 菱形继承
菱形继承是多继承的一种特殊情况。
菱形继承有数据冗余和二义性的问题。
7.4 虚拟继承virtual
虚拟继承可以解决菱形继承的二义性和数据冗余的问题。