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

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

#include <iostream>

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;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
拷贝构造函数参数传递通常是通过引用来实现的。引用是一种特殊的变量类型,它允许我们使用已存在的变量作为参数传递函数,而不是创建一个新的副本。在拷贝构造函数中,通常使用const引用作为参数类型,以确保被传递的对象不会被修改。这样可以避免不必要的内存开销和复制操作。 当以拷贝的方式初始化一个对象时,会调用一个特殊的构造函数,即拷贝构造函数。如果程序员没有显式地定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数会使用已存在对象的成员变量来对新对象的成员变量进行一一赋值。换句话说,它会将已存在对象的属性值复制给新对象。这样,通过拷贝构造函数,我们可以在创建新对象时,传递一个已存在对象作为参数,从而实现对象的拷贝和初始化。 在实际编程中,我们也可以自定义拷贝构造函数,以便根据程序需求来实现更精确的拷贝操作。自定义的拷贝构造函数可以有不同的参数类型,但通常会使用const引用来传递被拷贝的对象。这样可以避免对被拷贝对象进行修改,同时也可以提高性能,避免不必要的复制和内存开销。 总结来说,拷贝构造函数参数传递通常使用const引用来实现,以确保被传递的对象不会被修改,同时也提高性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++拷贝构造函数(复制构造函数详解](https://blog.csdn.net/ccc369639963/article/details/122905329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Santiago

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值