通过地址调用类中函数成员地址来调用函数

不说废话,直接上代码。看代码理解。

//=====================通过地址调用类中函数成员地址来调用函数==============================
class Base
{
	int i;
public:
	virtual void f1()
	{
		std::cout << "Base's f1(function in )" << std::endl;
	}
	virtual void f2()
	{
		std::cout << "Base's f2(function in )" << std::endl;
	}
	virtual void f3(const char * a)
	{
		std::cout << "Base's f3(function in ):" << a<<std::endl;
		__FUNCTION__;
	}
};
class Base2
{
public:
	int a;
public:
	virtual void showa()
	{
		std::cout << "Base2::showa" << std::endl;
	}
	virtual void showb()
	{
		std::cout << "Base2::showb" << std::endl;
	}
	virtual void showc()
	{
		std::cout << "Base2::showc" << std::endl;
	}
};

void ShowWtableContent(char * classname,void *pObj,int vindex)
{
	unsigned long* pAddr = NULL;  //任何一个指针本身的类型都是unsigned long int型 = unsigned long 型
	pAddr = reinterpret_cast<unsigned long*>(pObj);
	pAddr = (unsigned long*)*pAddr;
	std::cout << classname << "s vtable[" << vindex << "]:0x" << (void*)pAddr[vindex] << std::endl;
	const char *bx = "12345678";
	if (vindex != 2)
	{
		((void(*)(void))pAddr[vindex])();
	}
	else {
		if (vindex == 2)
		{
			((void(*)(const char*))pAddr[vindex])(bx);
		}
	}
}
//=====================通过地址调用类中函数成员地址来调用函数==============================
int main()
{	
	//Base *b1=new Base;
	Base b1 ; //演示中的原代码的
	ShowWtableContent("Base",&b1,0);
	ShowWtableContent("Base", &b1, 1);
	ShowWtableContent("Base", &b1, 2);
	Base2 b2;
	cout << sizeof(b2) << endl;
	cout << &b2 << endl;    //对象首地址
	cout << (int*)&b2 << endl;    //指针首地址,(int*)强制类型转换是为了取四个字节的内容
	cout << *(int*)&b2 << endl;    //指针的内容,即虚表的地址
	cout << *((int*)*(int*)&b2) << endl;    //虚表第一个元素即虚函数showa()的地址
	cout << *((int*)(*(int*)&b2) + 1) << endl;    //第二个元素的地址
	/*以上代码是纯地址取类成员函数操作
	*这里可能有人奇怪虚表的地址不就是第一个元素的地址,为什么这里要加(int*)?
	*代码的后面会有解释
	*/
	typedef void(*Fun)(void);    //重命名函数指针类型
	Fun pfun;
	pfun = (Fun)*(int*)*(int*)&b2;    //强制类型转换为该函数指针类型
	b2.showa();
	pfun();
	pfun = (Fun)*(((int*)*(int*)&b2)+1);    //强制类型转换为该函数指针类型
	b2.showb();
	pfun();
	pfun = (Fun)*(((int*)*(int*)&b2) + 2);    //强制类型转换为该函数指针类型
	b2.showc();
	pfun();
	return 0;
}
以上代码是纯地址取类成员函数,变为函数后的操作
	加(int*)的原因:
其实它(int*)的作用是一样的,都是为了取四个字节的内容,至于为什么要这样做就涉及到了指针的基础知识。
我们都知道定义指针变量时一定要声明类型,不同于其他基础类型,定义int变量就是4个字节,定义char变量是1个字节,定义short变量就是2个字节,我们都知道无论是什么类型的指针都占4个字节,那么声明类型到底有什么用呢?
它就是为了限定指针在内存上取变量的长度,这样说可能不太清楚,我们来看代码:
#include<stdio.h>
int main()
{
        int a=134480385;
        int* pa=&a;
        char* pb=&a;
        short* pc=&a;
        printf("*pb=%d  *pc=%d  *pa=%d\n",*pb,*pc,*pa);
}
显示:*pb=1 *pc=513 *pa=134480385
a的二进制表示为:0000 1000 0000 0100 0000 0010 0000 0001
这样大家看的应该就比较清楚了,char类型的指针pb只会取一个字节,因此取出的数为0000 0001,即1
short类型的指针pc会取两个字节,因此取出的数为0000 0010 0000 0001,即513
同理,int类型指针取四个字节,会全部取出。
好了,现在回到虚表中的(int*)中,现在大家是不是能够理解为什么了呢。
如果不加(int*)编译器就不知道应该取的长度
在取虚表地址的代码中,我们可以看到这个虚表指针是没有名字的,
因此就无法像我们平常使用指针那样直接调用变量来引用内容,
只能通过*(int*)&b的方式获取指针的内容,*(int*)&b就是获取对象b空间上的前四个字节的内容。
同理,虚表虽然像一个指针数组,但是我们不知道它的名字,
也就无法像原来使用数组那样直接使用数组名和下标的方式使用,
只能通过地址来调用内容。*(int*)*(int*)&b,就是在虚表的空间上取四个字节,
它就是第一个虚函数的地址。(int*)(*(int*)&f)+1是第二个元素的地址,
加*取它的内容,即第二个虚函数的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值