1.继承概念相关
1.1 概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保
持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象
程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继
承是类设计层次的复用。
1.2 定义格式
class Student : public Person
{
public:
int _num;
int _major;
};
代码中,Student是子类/派生类,Person是父类/基类。基本格式是子类:继承方式 父类。
继承方式可以省略,class默认是私有继承。struct默认是公有继承。
1.3 继承方式
继承方式一共有三种,和访问限定符一样,公有继承public,私有继承private,保护继承protect。
与访问限定符结合着看,继承优先度高的,按继承方式限定子类的成员。
基本上只需要看公有继承。公有继承父类的子类与父类成员限定关系一样。
(1)private成员在子类中不可见,意思是此类成员确实被继承了,但是无论在类外还是类里面都无法被访问。
2.基类和派生类对象赋值转换
派生类对象可以赋值给 基类的对象 / 基类的指针 / 基类的引用。但是基类对象不能赋值给派生类对象。
3.继承中的作用域
1. 在继承体系中基类和派生类都有独立的作用域。
2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,
也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)
3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
4.派生类默认成员函数
派生类自己生成默认的构造函数,拷贝构造,赋值重载,析构函数,这四个函数和类与对象中讲的一样,对内置类型不处理,自定义类型会去调用它们的函数。
而对于派生类继承基类过来的成员,会去调用基类的函数。
基类和派生类的析构函数构成隐藏,由于多态,统一会命名为destructtor()。
每个析构函数会自动调用父类的析构,保证先析构子类,再析构父类。
5.static静态成员
如果基类定义了一个静态成员,则整个继承体只会有一个这样的成员。
6.友元与继承
友元函数不能被继承,因为不属于类里面的成员函数。
7.多继承与菱形继承
单继承:一个子类只有一个直接父类时称这个继承关系为单继承。
多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承。
菱形继承是多继承的一种特殊情况。
![](https://i-blog.csdnimg.cn/blog_migrate/a158bf4a28ed0edadff8665f4eb8c62d.png)
菱形继承具有二义性和冗余性的缺点。
Student和Teacher都继承了Person,它们同时具备Person的成员,因此在调用时无法明确访问的时哪一个。
显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决。
虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和
Teacher的继承Person时使用虚拟继承,即可解决问题。
虚拟继承的关键词是virtual。
class Person
{
public :
string _name ; // 姓名
};
class Student : virtual public Person
{
protected :
int _num ; //学号
};
class Teacher : virtual public Person
{
protected :
int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
string _majorCourse ; // 主修课程
};
8.继承与组合
public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。
继承是一种白箱复用,
基类的
内部细节对子类可见 。继承一定程度破坏了基类的封装,基类的改变,对派生类有很
大的影响。派生类和基类间的依赖关系很强,耦合度高。
组合是一种黑箱复用,代码维护性好,耦合度低,对象的内部细节是不可见的,有助于帮助每个类都被良好地封装。
车与车品牌可以构成继承关系。轮胎与车可以构成组合的关系。