希望文章能对你有所帮助,有不足的地方请在评论区留言指正,一起交流学习!
1.多态
1.1 什么是多态
不同的对象(派生类和基类)执行同一个行为\事件产生的结果是不一样的;是多种状态的。
同一个接口,不同的实现;
即使用不同的派生对象 来调用同一个接口会产生不同的状态。 且函数接口继承于父类,父类也是可以调用的。
如下图,Person 为人,Student 继承了Person 的派生类,二者均调用一个函数,产生了多种状态,这种情况是怎么实现的呢

1.2 构成多态的条件
通过父类指针或者引用的调用虚函数
调用的函数必须是虚函数,且子类对虚函数完成重写。
调用区别多态调用: 被调函数,看指向的对象
2.普通调用看 当前对象的类型。
虚函数
在成员函数前面加上关键字 virtual , 并且基类的成员函数和派生类的成员函数的**返回值、函数名字以及参数列表(类型、 顺序、数量)相同,**参数列表相同不包含形参的名字啊。

特例
- 派生类的函数可以不加 virtual,也可以实现虚函数。(建议在使用的时候加上,好辨认)
- 协变: 虚函数的返回值 可以是父类和子类的引用或者指针,当然自身的父子引用以及其他父子类的引用和指针均可以,父类的引用必须是父类,子类的引用必须是子类。(完全没有必要)
为什么派生类中的函数可以不加 virtual
因为在基类中的函数已经加入 virtual ,表明此函数就是 虚函数,派生类的继承继承这个函数的性质,在不加 virtual 的时候也是虚函数。
重写是对函数体 的重新构建 ,其他的保持三同,重写还叫做是覆盖。
插入一个知识点

重写(覆盖)
重写,复用基类虚函数的函数签名和返回值**,** 提供函数更加具体的实现。 在编译层面上是通过虚函数表关联的**,** 被视为用同一个函数的不同形态**。同一接口的不同行为。**
在派生类中的函数名字 和基类相同 的成员函数,不是重写就是重定义。
注:函数标签就是函数名、参数列表和成员函数的 const限定符。
重定义(隐藏)
本质 :派生类 中只要存在与基类同名的函数 ,就会屏蔽基类 中所有同名函数。
总结:
重写是 "同一个函数的不同实现"(非新函数),依赖虚函数实现多态;
重定义是 "同名的不同函数"(新函数),仅存在名称巧合,无多态支持。
1.3.析构函数的多态(重点)
C++的类中将析构函数的函数名 统一处理 为 destructor,为了是让析构函数也构成多态。

但是特殊情况, 会造成内存泄漏

由于是指针或者引用调用,在这里实现多态,便可以实现

总结
- 为了构成多态析构函数的名字 统一为destructor()
- 子类不加virtual也算是析构函数的特权了,
- 基类 的析构函数 建议直接加入 virtual
1.4.C++11的关键字 override 和 final (类不被继承)
final 不让 函数重写 、不让类被继承,final表示类为最终的类,不可被继承


override 帮助派生类检测函数重新是否完成,没有重新,报错

将BuyTicket(),删除末尾的 t ,然后就不是函数重新,override检测还是是否符合三同。
设计不想被继承的类
1.私有 的成员函数在基类 中是不可见的,就是不可以使用,使用就会报错的。
2.派生类的构造函数必须调用基类构造函数
将父类的构造函数放入私有中,
cpp
class A
{
public:
static A CreatObj()
{
return A();
}
int a = 1;
private:
A()
{}
};
class B : public A
{
public:
private:
};

将父类的析构函数放入私有中,
cpp
class A
{
public:
static A* CreatObj()
{
return new A();
}
static void destroyObj(A* obj)
{
delete obj;
}
int a = 1;
private:
A()
{}
~A()
{}
};
class B : public A
{
public:
private:
};
cpp
A* obj = A::CreatObj(); // 创建对象
A::destroyObj(obj);
我试了 :仅设析构私有可阻止继承,但基类自身的对象无法正常销毁(栈对象无法创建、堆对象无法 delete),因此实际中很少单独这么用,就是老老实实用私有构造函数防止继承吧
1.5.总结
- 多态针对是成员函数(非静态(引用指针调用))
- 虚函数的继承,派生类继承的是接口的使用权,目的是为了重写。
- 实现继承(普通的继承)派生类继承了基类函数,可以使用函数,继承的是函数的实
现

