C++ -- 虚函数表

1、虚函数表

虚函数表是一个存储虚函数地址的表格,用于实现C++的多态机制。

每个包含虚函数的类都会由编译器生成一个虚函数表,简称V-Table。

这个表记录了类中的所有虚函数的函数指针,实现虚函数的动态绑定。

当一个类含有虚函数时,编译器会为该类加上一个成员变量,即一个指向虚函数表的指针vptr,

这个指针通常位于对象内存布局的开始位置。每个由该类派生出来的对象都会包含这个vptr,并且指向同一个虚函数表。

虚函数表创建的时间:在一个类构造的时候,创建这张虚函数表,而这个虚函数表是供整个类所共有的。虚函数表的地址存储在对象最开始的位置。

首先了解下虚函数表:虚函数表其实就是函数指针的地址。函数调用的时候,通过函数指针所指向的函数来调用函数。

类的大小sizeof();

#include "stdafx.h"
#include "iostream"
using namespace std;
class A
{
public:
	virtual void func1();//指向虚函数表的指针,占4个字节。
	virtual void func2();
	virtual void func3();
private:
	int m;
	char ch; //字节对齐,成员变量占8个字节
};

class B:public A
{
private:
	A *p; //指针占4个字节
};

void main()
{
	cout<<"The size of class A is "<<sizeof(A)<<endl; //4+8=12
	cout<<"The size of class B is "<<sizeof(B)<<endl; //12+4=16
	system("pause");
}

输出:12,16

2、虚函数表内函数的存储

虚函数表的内容是根据类中的虚函数声明次序填入函数指针的。

当在派生类中改写虚函数时,虚表就会受到影响,表中的元素所指的函数地址将不再时基类的函数地址而是派生类的函数地址。

这种机制允许通过基类的指针或引用在运行时调用派生类的虚函数,实现了多态。

#include "stdafx.h"
#include "iostream"
using namespace std;
class A
{
public:
	virtual void func1(){cout << "Virtual A1 func1()"<<endl;}
	virtual void func2(){cout << "Virtual A2 func2()"<<endl;}
	virtual void func3(){cout << "Virtual A3 func3()"<<endl;}
	int m;
	char ch;
};

class B:public A
{
public:
	virtual void func4(){cout << "Virtual B1 func4()"<<endl;}
	int mb;
};
typedef void (*funp)();
void main()
{
	A a;
	B b;
	funp pFunc;
	cout<<"The size of class A is "<<sizeof(A)<<endl;
	cout<<"The size of class B is "<<sizeof(B)<<endl;
	cout<<"a的虚函数表的地址是:"<<(int)(int *)(&a)<<endl;
	cout<<"a的成员变量m的地址是:"<<(int)(int *)(&a.m)<<endl;
	cout<<"a的成员变量ch的地址是:"<<(int)(int *)(&a.ch)<<endl;

	cout<<"b的虚函数表的地址是:"<<(int)(int *)(&b)<<endl;
	cout<<"b的成员变量mb的地址是:"<<(int)(int *)(&b.m)<<endl;
	cout<<"b的成员变量ch的地址是:"<<(int)(int *)(&b.ch)<<endl;
	cout<<"b的成员变量mb的地址是:"<<(int)(int *)(&b.mb)<<endl;
	
	pFunc = (funp)(*(int *)(*(int *)&b));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+1));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+2));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+3));
	pFunc();
	system("pause");
}

输出结果显示:


3、基类被隐藏

子类和基类函数名相同,参数不同,基类被隐藏。

#include "stdafx.h"
#include "iostream"
using namespace std;
class A
{
public:
	virtual void func1(){cout << "Virtual A1 func1()"<<endl;}
	virtual void func2(){cout << "Virtual A2 func2()"<<endl;}
	virtual void func3(){cout << "Virtual A3 func3()"<<endl;}
	int m;
	char ch;
};

class B:public A
{
public:
	virtual void func1(int mb){cout << "Virtual B1 func4()"<<endl;}
	int mb;
};
typedef void (*funp)();
void main()
{
	A a;
	B b;
	funp pFunc;
	cout<<"The size of class A is "<<sizeof(A)<<endl;
	cout<<"The size of class B is "<<sizeof(B)<<endl;
	cout<<"a的虚函数表的地址是:"<<(int)(int *)(&a)<<endl;
	cout<<"a的成员变量m的地址是:"<<(int)(int *)(&a.m)<<endl;
	cout<<"a的成员变量ch的地址是:"<<(int)(int *)(&a.ch)<<endl;

	cout<<"b的虚函数表的地址是:"<<(int)(int *)(&b)<<endl;
	cout<<"b的成员变量mb的地址是:"<<(int)(int *)(&b.m)<<endl;
	cout<<"b的成员变量ch的地址是:"<<(int)(int *)(&b.ch)<<endl;
	cout<<"b的成员变量mb的地址是:"<<(int)(int *)(&b.mb)<<endl;
	
	pFunc = (funp)(*(int *)(*(int *)&b));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+1));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+2));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+3));
	pFunc();
	b.A::func1(); //调用class A中的函数func1(),不加作用域会报错
	b.func1(5); //带参数的func1(),调用B类的。
	system("pause");
}

输出结果显示:


4、基类被覆盖

派生类和基类的函数同名,参数也相同,基类的函数被覆盖

#include "stdafx.h"
#include "iostream"
using namespace std;
class A
{
public:
	virtual void func1(){cout << "Virtual A1 func1()"<<endl;}
	virtual void func2(){cout << "Virtual A2 func2()"<<endl;}
	virtual void func3(){cout << "Virtual A3 func3()"<<endl;}
	int m;
	char ch;
};

class B:public A
{
public:
	virtual void func1(){cout << "Virtual B1 func1()"<<endl;} //和基类的函数同名,参数也相同,基类的函数被覆盖
	int mb;
};
typedef void (*funp)();
void main()
{
	A a;
	B b;
	funp pFunc;
	cout<<"The size of class A is "<<sizeof(A)<<endl;
	cout<<"The size of class B is "<<sizeof(B)<<endl;
	cout<<"a的虚函数表的地址是:"<<(int)(int *)(&a)<<endl;
	cout<<"a的成员变量m的地址是:"<<(int)(int *)(&a.m)<<endl;
	cout<<"a的成员变量ch的地址是:"<<(int)(int *)(&a.ch)<<endl;

	cout<<"b的虚函数表的地址是:"<<(int)(int *)(&b)<<endl;
	cout<<"b的成员变量mb的地址是:"<<(int)(int *)(&b.m)<<endl;
	cout<<"b的成员变量ch的地址是:"<<(int)(int *)(&b.ch)<<endl;
	cout<<"b的成员变量mb的地址是:"<<(int)(int *)(&b.mb)<<endl;
	
	pFunc = (funp)(*(int *)(*(int *)&b));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+1));
	pFunc();
	pFunc = (funp)(*((int *)(*(int *)&b)+2));
	pFunc();
	system("pause");
}

输出结果显示:


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值