C++中的虚函数表解析

单继承虚函数表

  • 什么是虚函数表?
    含有虚函数的类实例化出的对象内存会多出四个字节,前四个字节存储一个指针,叫虚表指针,这个指针指向一张表,这张表按顺序存储了重写的虚函数,叫虚(函数)表
基类虚表的构建原则
  • 将基类虚函数按照其在类中声明的先后顺序依次存放在虚表中。
派生类虚表构建原则
  1. 只要基类中有虚函数,即使派生类没有重写基类的虚函数,派生类也会有自己的虚表指针,这个指针指向的虚表与基类的虚表内容完全相同,而是对基类虚表的一份拷贝。
class A{
public:
	virtual void print1(){
		cout<<"A::print()"<< endl;
	}
	virtual void print2(){
		cout << "A::print()" << endl;
	}
	virtual void print3(){
		cout << "A::print()" << endl;
	}	
	int _a;
};

class B:public A{
public:
	//派生类B并没有重写基类的虚函数
	int _b;
};
int main(){
	A a;
	B b;
	//cout << sizeof(A) << endl;//8 int _a+虚表指针 
	//cout << sizeof(B) << endl;//12 int _a+int _b+虚表指针
	b._a = 1;
	b._b = 2;
 	return 0;
}

在这里插入图片描述

  1. 如果派生类重写了基类的虚函数,编译器将会使用派生类自己的虚函数覆盖表中的相同偏移量位置的基类虚函数。
  2. 派生类中新增加的虚函数也会存放在虚表中,并按照在类中声明的顺序依次存放在重写的虚函数后面。
class A{
public:
	virtual void print1(){
		cout<<"A::print1()"<< endl;
	}
	virtual void print2(){
		cout << "A::print2()" << endl;
	}
	virtual void print3(){
		cout << "A::print3()" << endl;
	}
	int _a;
};

class B:public A{
public:
    virtual void print4(){//新增的虚函数
		cout << "B::print4()" << endl;
	}
	virtual void print1(){
		cout << "B::print1()" << endl;
	}
	//A::print2()没有重写
	virtual void print3(){
		cout << "B::print3()" << endl;
	}
	virtual void print5(){
		cout << "B::print5()" << endl;
	}
	int _b;
};
int main(){
	A a
	B b;
	b._a = 1;
	b._b = 2;
 	return 0;
}

在这里插入图片描述

多继承虚函数表

class A2{
public:
	virtual void print3(){
		cout << "A2::print3()" << endl;
	}
	virtual void print4(){
		cout << "A2::print4()" << endl;
	}
	int _a2;
};
class B:public A1,public A2{
public:
	virtual void print1(){
		cout << "B::print1()" << endl;
	}
	virtual void print3(){
		cout << "B::print3()" << endl;
	}
	virtual void print5(){
		cout << "B::print5()" << endl;
	}
	int _b;
};
//打印虚表
typedef int(*pVF)();
void printvft(A1& a, string s){
	cout << s << endl;
	pVF* p = (pVF*)*(int*)&a;
	while (*p){
		(*p)();
		p++;
	}
}
void printvft(A2& a, string s){
	cout << s << endl;
	pVF* p = (pVF*)*(int*)&a;
	while (*p){
		(*p)();
		p++;
	}
}
int main(){
	B b;
	b._a1 = 1;
	b._a2 = 2;
	b._b = 3;
	A1& a1 = b;
	A2& a2 = b;
	printvft(a1, "B从A1继承下来的虚表:");
	printvft(a2, "B从A1继承下来的虚表:");
 	return 0;
}

在这里插入图片描述

菱形继承虚函数表

class A{
public:
	virtual void print1(){
		cout << "A::print1()" << endl;
	}
	virtual void print2(){
		cout << "A::print2()" << endl;
	}
	virtual void print3(){
		cout << "A::print3()" << endl;
	}
	int _a;
};

class B1 :public A{
public:
	virtual void print1(){
		cout << "B1::print1()" << endl;
	}
	virtual void print4(){
		cout << "B1::print4()" << endl;
	}
	int _b1;
};
class B2 :public A{
public:
	virtual void print2(){
		cout << "B2::print2()" << endl;
	}
	virtual void print5(){
		cout << "B2::print5()" << endl;
	}
	
	int _b2;
};
class C :public B1, public B2{
public:
	virtual void print1(){
		cout << "C::print1()" << endl;
	}
	virtual void print2(){
		cout << "C::print2()" << endl;
	}
	virtual void print3(){
		cout << "C::print3()" << endl;
	}
	virtual void print4(){
		cout << "C::print4()" << endl;
	}
	/*virtual void print5(){
		cout << "C::print5()" << endl;
	}*/
	virtual void print6(){
		cout << "C::print6()" << endl;
	}
	int _c;
};

typedef int(*pVF)();
void printvft(B1& b, string s){
	cout << s << endl;
	pVF* p = (pVF*)*(int*)&b;
	while (*p){
		(*p)();
		p++;
	}
}
void printvft(B2& b, string s){
	cout << s << endl;
	pVF* p = (pVF*)*(int*)&b;
	while (*p){
		(*p)();
		p++;
	}
}
int main(){
	C c;
	c.B1::_a = 1;
	c.B2::_a = 2;
	c._b1 = 3;
	c._b2 = 4;
	c._c = 5;

	B1& b1 = c;
	B2& b2 = c;
	printvft(b1, "c从B1继承下来的虚表:");
	printvft(b2, "c从B1继承下来的虚表:");
	return 0;
}

在这里插入图片描述

从上面两张图发现:

  • 菱形继承中只要有虚函数,也会一步步实现多态的重写。

菱形虚拟继承暂时还未弄明白,请各位指教。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值