C++多态

多态即是当不同的对象完成时产生不同的状态
多态的构成条件
多态是在不同继承关系的类对象,去调用同一函数产生不同行为
构成多态同时要满足:

  • 必须通过基类的指针或者引用调用虚函数
  • 被调用的函数必须是虚函数,同时派生类中必须对虚函数进行重写

虚函数
虚函数 : 被virtual修饰的类成员函数称为虚函数
虚函数的重写(覆盖) : 派生类中有一个和积累中完全相同的虚函数(返回值类型,函数名字,参数列表),此时就是派生类的虚函数重写了基类的虚函数
特例:

  1. 协变(基类和派生类函数返回值类型不同)
    派生类重写基类虚函数时,与积累虚函数返回值类型不同,即派生类虚函数返回派生类对象的指针或者引用,基类返回基类对象的指针或者引用时称协变
  2. 析构函数的重写(派生类和基类析构函数名字不同)
    如果基类的析构函数是虚函数,此时派生类的析构函树如存在定义,都与基类构成析构函数重写,无关函数名不同或者派生类析构函数有无virtual修饰.

C++11 override和final

  1. override : 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写报错
class person{
public:
virtual void Init(){}
};
class student :public person {
public:
virtual void Init() override {}
};
  1. final : 修饰虚函数,表示该虚函数不能被继承
class person{
public:
virtual void Init() final {}
};
class student :public person {
public:
virtual void Init()  {}
};

重载,覆盖(重写),隐藏(重定义)
在这里插入图片描述
抽象类
在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承
接口继承和实现继承
普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数

虚函数表

class person{
public:
	virtual void func() {}
private:
	int _a = 1;
};

person类的大小在32位下是8bytes. 此时同时存在_vfptr和_a, _vfptr 为虚函数表指针(v代表virtual,f代表function) 一个含有虚函数的类中至少有一个虚函数表指针,因为虚函数的地址要被放在虚函数表中(虚表) .

class Base
{
public:
	virtual void Func1()
	{
		cout << "Base::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base::Func2()" << endl;
	}
	void Func3()
	{
		cout << "Base::Func3()" << endl;
	}
private:
	int _b = 1;
};


class Derive : public Base
{
public:
	virtual void Func1()
	{
		cout << "Derive::Func1()" << endl;
	}
private:
	int _d = 2;
};
int main()
{
	Base b;
	Derive d;
	return 0;
}
  • 派生类对象d中有一个续表指针,d对象由两部分构成,一部分是父类继承下来的成员,虚表指针也就是存在此,另一部分是自己的成员
  • 基类b和派生类d对象虚表是不一样的,Func1完成重写,多所以虚表存的是重写的Derive::Func1,多以虚函数重写也称覆盖,覆盖就是指虚表中虚函数的覆盖.
  • Func2继承下来是虚函数,放进虚表,Func3同样继承,但是不是虚函数,不会放进虚表
  • 虚函数表本质是一个存虚函数指针的指针数组,数组最后放一个nullptr.
  • 虚表的生成:
    a.先将基类中的虚表内容拷贝一份到派生类虚表中
    b.如果派生类重写了基类中某个虚函数,派生类自己的虚函数覆盖虚表中基类的虚函数
    c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后
  • 虚表存的是虚函数指针,虚函数和普通函数一样存在代码段,同时对象中存的是虚表指针,在vs下虚表存在代码段.
  • 满足多态以后的函数调用,不是在编译时确定,是在运行起来后到对象中去找的.同时不满足多态条件函数调用时编译确认好的

静态绑定和动态绑定

  1. 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为,也称为静态多态,比如:函数重载
  2. 动态绑定又称后期绑定(晚绑定),是在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数,也称为动态多态。

单继承+多态对象模型
派生类中重写的虚函数覆盖基类中的虚函数
基类中未重写的函数不变
派生类中新加虚函数直接将虚函数指针存入虚表
多继承+多态对象模型
多继承派生类中未重写的虚函数放在第一个继承基类部分的虚函数表中

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值