类的成员函数做参数传递详解

由于类的成员函数所遵循的函数调用规范是__thiscall,这个规范的效果是在调用成员函数时,将this指针同时压栈;而普通函数(包括全局函数、静态函数以及类的静态成员函数)的调用规范一般为 _cdecl和_stdcall,并没有这个this指针。因此,类的成员函数无法直接赋值给普通函数指针。
本文详细介绍了类的成员函数赋值给函数指针的方法。
本文重点参考了以下文章:https://bbs.csdn.net/topics/390288833

#include 

class Test
{
public:
	// 示例1,类内部的typeDef函数声明,属于Test成员,声明时必须加Test声明作用域,且赋值的函数必须为Test成员.
	// 核心原理为类的成员函数实际上参数压栈时多了一个this指针,所以匹配时会做类型检查
	typedef void (Test::*MEMBERFUNC) (); 

	// 示例2,类内部的typeDef函数声明,不属于Test成员,声明时不能加Test声明作用域,赋值的函数为全局函数
	typedef void(*GLOBALFUNC) (); 

	Test() { m_iMember = 0; }
	~Test() {};

	void Print() 
	{
		std::cout << "this is member fun in Test\n";
	}

	int Simple(int i)
	{
		std::cout << "user input " << i << std::endl;
		return i;
	}

	int m_iMember;
};

//示例3,类外部的typeDef函数声明,属于Test成员,声明时需要加Test声明作用域,赋值的函数必须为Test成员
typedef void (Test::*MEMBERFUNC2) (); 

//示例4,类外部的typeDef函数声明,不属于Test成员,声明时不能加Test声明作用域,赋值的函数不能为Test成员函数
typedef void(*GLOBALFUNC)(); 

void GlobalFunc()
{
	printf("this is external GlobalFunc\n");
}

//这个模板函数,实际上可以适配所有相同类型的类成员函数;也就是说,根据类类型T的不同,调用不同类的成员函数
template<class T>
void GlobalTemplateFun(int j, T* obj, int (T::*pFun)(int))
{
	std::cout <<"全局模板函数输出:"<< (obj->*pFun)(j)<<std::endl;
}

int main()
{
	Test t;
	Test::MEMBERFUNC pMemFunc = NULL;
	Test::GLOBALFUNC pGlobalFunc1 = NULL;
	MEMBERFUNC2 pMemFunc1 = NULL;
	GLOBALFUNC pGlobalFunc2 = NULL;

	//此句打印成员函数地址
	printf("the addr of Test::testfunc is %p\n", &Test::Print);

	//实例1:类中定义了成员函数指针类型,该类型应当赋值成员函数地址
	printf("demo1:\n");
	pMemFunc = &Test::Print;
	//pMemFunc();					//无法输出,pfunc的实际指向是类的成员,必须依赖类的对象或者静态化来输出;
	(t.*pMemFunc)();				//.*运算符为成员函数的解除引用
	//pMemFunc = &GlobalFunc;		//无法转换,赋值函数必须为类成员类型
	
	//实例2:类中定义了全局函数指针类型,该类型应当被赋值全局函数地址
	printf("demo2:\n");
	//pGlobalFunc1 = &Test::Print;	//无法转换,赋值函数必须为全局void (*)()类型,不能为类成员
	pGlobalFunc1 = &GlobalFunc;		//&可用可不用,全局函数名表示函数地址
	pGlobalFunc1();	//可以输出

	//实例3:类外定义了成员函数指针类型,该类型应当赋值成员函数地址
	printf("demo3:\n");
	pMemFunc1 = &Test::Print;
	//pMemFunc1();					//无法编译,因为pFunc1本质来讲是个成员函数
	(t.*pMemFunc1)();				//借助类对象进行输出
	//pMemFunc1 = GlobalFunc;		//无法转换,全局函数无法赋值给成员函数指针

	//实例4:全局函数指针应该被赋值全局函数地址
	printf("demo4:\n");
	//pGlobalFunc2 = &Test::Print;	//无法转换,全局函数地址无法赋给成员函数指针
	//pGlobalFunc2();				//可以输出,但注意测试并没有被赋值
	pGlobalFunc2 = &GlobalFunc;
	pGlobalFunc2();

	//接下来,我们看看如何给一个成员变量指针赋值
	//成员变量的地址是多少呢?成员变量在每个类对象中都有副本,因此每个对象的成员变量均有地址
	printf("the addr of t.m_iMember is %p\n", &t.m_iMember);
	int (Test::* pMemFunc2)(int);	
	pMemFunc2 = &Test::Simple;		
	int Test::* pInt;				//声明了一个成员变量指针
	pInt = &Test::m_iMember;		//给成员变量指针赋值
	t.*pInt = 3;	//也可以写成(&t)->*pInt = 3;	
	(t.*pMemFunc2)(t.*pInt);
	//GlobalTemplateFun(8, &t, &Test::Simple);	//这是一种简单写法
	GlobalTemplateFun(8, &t, pMemFunc2);	

	return 0;
}

你可能感兴趣的:(C/C++基础知识,c++)