栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

//=====================通过地址调用类中函数成员地址来调用函数==============================
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<(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;    //第二个元素的地址
	
	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
int main()
{
        int a=134480385;
        int* pa=&a;
        char* pb=&a;
        short* pc=&a;
        printf("*pb=%d  *pc=%d  *pa=%dn",*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是第二个元素的地址,
加*取它的内容,即第二个虚函数的地址。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/330148.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号