C++中的覆盖、多态

一、虚函数、覆盖、多态
虚函数:成员函数在定义时添加了 virtual 关键字,这种函数叫虚函数
覆盖:如果在子类中实现与父类中的虚函数具有相同的函数,那么子类中的成员函数会覆盖父类中的成员函数
多态:如果子类中的成员函数对父类中的成员进行了覆盖,当一个指向子类的父类指针或引用了子类的父类引用,使用它调用虚函数,然后根据实际的调用对象调用子类中的覆盖函数,而不是父类中的虚函数,这种语法现象叫多态

多态的意义在于,同一种类发出同一种调用,而产生不同的反应


二、覆盖、重载、隐藏
满足覆盖(重写)的条件:
a、必须是成员函数
b、必须是虚函数
c、函数签名必须相同
d、如果返回值是基本类型则必须相同(否则会产生编译错误)
e、如果是类类型则必须是父子类关系的指针或引用(必须能进程自动类型转换)

满足重载的条件:
a、必须在同一作用域下
b、函数名相同但是参数列表不同
c、const属性相同
d、返回值的类型不会影响重载

满足隐藏的条件:
在父子类之间名字相同的标识符,只要还构成覆盖,则必定构成隐藏

三、多态的条件
1、多态特性除了父子类之间要构成覆盖,还必须是父类以指针或引用的方式指向子类

2、当指针或引用已经构成多态时,此时调用成员所传的this指针再调用成员函数时也可以构成多态

3、在子类的构造函数执行前会先调用父类的构造函数,如果调用了被覆盖的虚函数,由于子类还没有构造完成,因此只能是调用父类中的虚函数
构造函数在进入函数体执行时,类中看的见的资源已经全部构造完成

4、在子类的析构函数执行完成后会再调用父类的析构函数,如果调用被覆盖的虚函数,由于子类已经析构完成已经不能算是完整的子类了,因此只能调用父类中的虚函数


四、纯虚函数和抽象类
1、纯虚函数
class A
{
public :
virtual void test(void) =0;
virtual void test(void) const=0;
}
a、纯虚函数不需要被实现,如果非要实现也不能在类中,必须要在类外(虚函数)
b、纯虚函数如果想调用必须在子类中覆盖,然后以多态的方式调用

2、抽象类
成员函数中有纯虚函数的叫抽象类,这种类不能创建对象。
如果子类继承了抽象类,则必须把父类中的纯虚函数覆盖了,否则它也变成了抽象类不能被实体化。
因此抽象类只能以指针或引用的方式指向子类来调用自己的非纯虚函数

3、纯抽象类
所有的成员函数都是纯虚函数,这种类叫纯虚函数
面向对象的四大特性:抽象、封装、继承、多态
纯抽象类可以是封装类的一个过程,同时抽象类也可以当作一个统一的接口类

4、纯抽象类的应用场景
回调模式:
函数a由程序员小明实现完成,如果在此时他想调用小光实现的函数b 1970年
函数b由程序员小光实现完成,小光在1980年出生
命令模式:
输入一个指令然后执行对应的操作
生产者与消费者模式
单例模式(饿汉、懒汉)
工厂模式:
一个类以专门制造其它类为己任,这种编程模式叫工场模式
MVC模式

五、C++中的强制类型转换
1、C语言中的强制类型转换还能继续使用,但是不安全
2、C++的强制类型转换使用很麻烦,其实C++之父不建议使用强制类型转换,一旦代码中需要使用强制类型转换说明代码设计的不合理,强制类型转换是一种亡羊补牢的方法

static_cast 静态类型转换
1、自健类型的强制转换
2、void*与其它类型指针的转换
3、父子类型之间的指针转换

const_cast 去常类型转换

reinterpret_cast 重解释类型转换
整数与指针之间的类型转换

dynamic_cast 动态类型转换
用于构成多态的父子类之间的指针类型转换

六、虚函数表
1、什么是虚函数表,当一个类中有虚函数时,编译器会为这个分配一个表专门记录这些虚函数,在类中会有一个隐藏的指针成员来指向这张表
2、如何证明这张表存在
有虚函数的类会比没有虚函数的类(相同中的)多4字节,还会有添加补齐和对齐
3、一个类只有一张虚函数表,所有对象共享一张虚函数表
4、一般对象的前四个字节是指向虚函数表的指针变量

七、动态类型绑定
1、当使用父类的指针或引用指向子类时,编译器并没有立即生成调用函数的指针,而生成了一段代码,用来检查指针指向的真正的对象是什么类型
2、在代码真正运行时才通过对象的指针找到指向虚函数的成员指针
3、再通过成员指针访问到虚函数表,再从中找到调用的函数地址
4、使用多态会产生额外的一些代码和调用,因此使用多态会降低代码的执行速度

八、类的信息
1、在C++中,使用typeid可以获取类的一些信息,以此来确定指针指向的到底是什么类
2、typeid可以直接使用来判断是否是同一种类型
typeid(标识符)==typeid(标识符)
3、typeid(标识符).name() 获取类型名,以字符串的形式呈现
4、如果typeid(指针)只能获取到指针的类型,typeid(*指针)可以获取到对象实际的类型信息

九、虚析构
1、如果通过父类指针或引用指向子类对象,当使用delete释放对象时,此时只能调用父类的析构函数,如果在子类中使用new/malloc申请的内存资源,那么将导致内存泄露

2、解决方法是把父类的析构函数设置为虚函数

3、在设计类时如果析构函数什么都不需要做,编译器也会生成一个空的析构函数,但这样的话会让继承它的子类有安全隐患

4、最好把所有的析构函数都设置为虚函数


猜你喜欢

转载自www.cnblogs.com/xiwen2017/p/9473844.html