C++多态虚函数表详解(多重继承、多继承情况)

多态内存分布

假设有一个基类ClassA,一个继承了该基类的派生类ClassB,并且基类中有虚函数,派生类实现了基类的虚函数。
我们在代码中运用多态这个特性时,通常以两种方式:
(1) ClassA *a = new ClassB();
(2) ClassB b; ClassA *a = &b;

以上两种方式都是用基类指针去指向一个派生类实例,区别在于第1个用了new关键字而分配在堆上,第2个分配在栈上。

在这里插入图片描述

类的虚函数表与类实例的虚函数指针

如果一个类中有虚函数,那么该类就有一个虚函数表。这个虚函数表是属于类的,所有该类的实例化对象中都会有一个虚函数表指针去指向该类的虚函数表。
第一部分的图中我们也能看到,一个类的实例要么在堆上,要么在栈上。也就是说一个类可以有很多很多个实例。但是一个类只能有一个虚函数表。在编译时,一个类的虚函数表就确定了,这也是为什么它放在了只读数据段中。

在这里插入图片描述

多继承

class ClassA
{
public:
	ClassA() { cout << "ClassA::ClassA()" << endl; }
	virtual ~ClassA() { cout << "ClassA::~ClassA()" << endl; }

	void func1() { cout << "ClassA::func1()" << endl; }
	void func2() { cout << "ClassA::func2()" << endl; }

	virtual void vfunc1() { cout << "ClassA::vfunc1()" << endl; }
	virtual void vfunc2() { cout << "ClassA::vfunc2()" << endl; }
private:
	int aData;
};

class ClassB : public ClassA
{
public:
	ClassB() { cout << "ClassB::ClassB()" << endl; }
	virtual ~ClassB() { cout << "ClassB::~ClassB()" << endl; }

	void func1() { cout << "ClassB::func1()" << endl; }
	virtual void vfunc1() { cout << "ClassB::vfunc1()" << endl; }
private:
	int bData;
};

class ClassC : public ClassB
{
public:
	ClassC() { cout << "ClassC::ClassC()" << endl; }
	virtual ~ClassC() { cout << "ClassC::~ClassC()" << endl; }

	void func2() { cout << "ClassC::func2()" << endl; }
	virtual void vfunc2() { cout << "ClassC::vfunc2()" << endl; }
private:
	int cData;
};

在有继承情况下,只要基类有虚函数,子类不论实现或没实现,都有虚函数表。基类的虚函数表和子类的虚函数表不是同一个表。
(1) ClassA是基类, 有普通函数: func1() func2() 。虚函数: vfunc1() vfunc2() ~ClassA()
(2) ClassB继承ClassA, 有普通函数: func1()。虚函数: vfunc1() ~ClassB()
(3) ClassC继承ClassB, 有普通函数: func2()。虚函数: vfunc2() ~ClassB()

在这里插入图片描述
ClassB继承与ClassA,其虚函数表是在ClassA虚函数表的基础上有所改动的,变化的仅仅是在子类中重写的虚函数。如果子类没有重写任何父类虚函数,那么子类的虚函数表和父类的虚函数表在内容上是一致的。

ClassA *a = new ClassB();
a->func1();                    // "ClassA::func1()"   隐藏了ClassB的func1()
a->func2();                    // "ClassA::func2()"
a->vfunc1();                   // "ClassB::vfunc1()"  重写了ClassA的vfunc1()
a->vfunc2();                   // "ClassA::vfunc2()"

上图中ClassA类型的指针a能操作的范围只能是黑框中的范围,之所以实现多态是因为子类的虚函数表内容与基类不同。
在这里插入图片描述

ClassA* a = new ClassC;
a->func1();          // "ClassA::func1()"   隐藏ClassB::func1()               
a->func2();          // "ClassA::func2()"	隐藏ClassC::func2()
a->vfunc1();	     // "ClassB::vfunc1()"	ClassB把ClassA::vfunc1()覆盖了
a->vfunc2();	     // "ClassC::vfunc2()"	ClassC把ClassA::vfunc2()覆盖了

ClassB* b = new ClassC;
b->func1();				// "ClassB::func1()"	有权限操作时,子类优先
b->func2();				// "ClassA::func2()"	隐藏ClassC::func2()
b->vfunc1();			// "ClassB::vfunc1()"	ClassB把ClassA::vfunc1()覆盖了
b->vfunc2();			// "ClassB::vfunc2()"	ClassC把ClassA::vfunc2()覆盖了

多重继承下的虚函数表

多重继承是指一个类同时继承了多个基类,假设这些基类都有虚函数,也就是说每个基类都有虚函数表。

class ClassA1
{
public:
	ClassA1() { cout << "ClassA1::ClassA1()" << endl; }
	virtual ~ClassA1() { cout << "ClassA1::~ClassA1()" << endl; }

	void func1() { cout << "ClassA1::func1()" << endl; }

	virtual void vfunc1() { cout << "ClassA1::vfunc1()" << endl; }
	virtual void vfunc2() { cout << "ClassA1::vfunc2()" << endl; }
private:
	int a1Data;
};

class ClassA2
{
public:
	ClassA2() { cout << "ClassA2::ClassA2()" << endl; }
	virtual ~ClassA2() { cout << "ClassA2::~ClassA2()" << endl; }

	void func1() { cout << "ClassA2::func1()" << endl; }

	virtual void vfunc1() { cout << "ClassA2::vfunc1()" << endl; }
	virtual void vfunc2() { cout << "ClassA2::vfunc2()" << endl; }
	virtual void vfunc4() { cout << "ClassA2::vfunc4()" << endl; }
private:
	int a2Data;
};

class ClassC : public ClassA1, public ClassA2
{
public:
	ClassC() { cout << "ClassC::ClassC()" << endl; }
	virtual ~ClassC() { cout << "ClassC::~ClassC()" << endl; }

	void func1() { cout << "ClassC::func1()" << endl; }

	virtual void vfunc1() { cout << "ClassC::vfunc1()" << endl; }
	virtual void vfunc2() { cout << "ClassC::vfunc2()" << endl; }
	virtual void vfunc3() { cout << "ClassC::vfunc3()" << endl; }
};

ClassA1是第一个基类,拥有普通函数func1(),虚函数vfunc1() vfunc2()。
ClassA2是第二个基类,拥有普通函数func1(),虚函数vfunc1() vfunc2(),vfunc4()。
ClassC依次继承ClassA1、ClassA2。普通函数func1(),虚函数vfunc1() vfunc2() vfunc3()。

在这里插入图片描述

  1. 在多继承情况下,有多少个有虚函数的基类就有多少个虚函数表指针。
  2. 当子类有多出来的虚函数时,添加在第一个虚函数表中,父类指针不能调用
  3. 当有多个虚函数表时,虚函数表的结果是0代表没有下一个虚函数表。" * "号位置在不同操作系统中实现不同,代表有下一个虚函数表。

	ClassA1 *a1 = new ClassC;
	a1->func1();               // "ClassA1::func1()"    隐藏子类同名函数
	a1->vfunc1();              // "ClassC::vfunc1()"    覆盖父类ClassA1虚函数
	a1->vfunc2();              // "ClassC::vfunc2()"    覆盖父类ClassA1虚函数
	没有a1->vfunc3(),父类没有这个虚函数

	ClassA2 *a2 = new ClassC;
	a2->func1();               // "ClassA2::func1()"    隐藏子类同名函数
	a2->vfunc1();              // "ClassC::vfunc1()"    覆盖父类ClassA2虚函数
	a2->vfunc2();              // "ClassC::vfunc2()"    覆盖父类ClassA2虚函数
	a2->vfunc4();              // "ClassA2::vfunc4()"   未被子类重写的父类虚函数

	ClassC *c = new ClassC;
	c->func1();                // "ClassC::func1()"
	c->vfunc1();               // "ClassC::vfunc1()"
	c->vfunc2();               // "ClassC::vfunc2()"
	c->vfunc3();               // "ClassC::vfunc3()"
	c->vfunc4();               // "ClassA2::func4()"

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值