使用可变参数传入任意数量的成员函数指针

注意:以下内容均基于个人理解,可能出现,误导,片面,错误等信息。请谨慎观看。

使用可变参数传入任意数量的成员函数指针

1.需求描述————————————————————————————————————————


最近在写一个C++控制台创建窗口项目,在封装类的时候想把 线程创建创建窗口 以及 消息处理 封装在一个函数体内,这样在调用时候只需要一个方法就可以完成三件事。

	void 想封装的创建窗口函数(){
		thread 创建线程({
			具体的创建窗口函数?();
			消息处理要运行的函数?(); //消息处理必须和窗口创建在同一线程内
		});
	}

2.问题原因————————————————————————————————————————


但是我定义的 创建的窗口的方法 有很多,信息处理的方法也有很多种
并不知道在外部调用时会使用哪一个创建方法和处理方法

	void 具体的创建窗口函数1()
	void 具体的创建窗口函数2()
	void 具体的创建窗口函数3()
	.....
	void 消息处理要运行的函数1()
	void 消息处理要运行的函数2()
	void 消息处理要运行的函数3()
	.....

如果想用重载的方法来封装 会导致工作量太大 而且调用的时候很容易混淆

3.解决方案————————————————————————————————————————


于是打算想通过 函数指针 进行封装
即在外部调用时传入两个参数(函数指针),对应两个过程的函数,然后在创建线程中分别对这两个函数进行调用
这样就变成了

	void 想封装的创建窗口函数 (void (*创建窗口函数指针)() , void (*消息处理函数指针)()){
		thread 创建线程({
			(*创建窗口函数指针)()
			(*消息处理函数指针)()
		})
	}
	//在外部调用时
	类名 Classobject();
	//创建一个窗口
	Classobject.想封装的创建窗口函数(Classobject.具体的创建窗口函数1,Classobject.消息处理要运行的函数1); 
	 //再创建一个不一样的窗口
	Classobject.想封装的创建窗口函数(Classobject.具体的创建窗口函数3,Classobject.消息处理要运行的函数1);

这样写编译器是一定会报错的 因为
我要调用的函数为 成员函数 所以在使用函数指针时需要 给函数指针加上命名空间
注意: 在外部调用时候,取成员函数地址时要在命名空间 加上 取址符 &

	&类名::*创建窗口函数指针

在函数体内部调用时候需要通过使用 this 指针来进行调用

	(this->*创建窗口函数指针)()

于是现在函数变成了这样

	void 想封装的创建窗口函数 (void (类名::*创建窗口函数指针)() , void (类名::*消息处理函数指针)()){
		thread 创建线程({
			(this->*创建窗口函数指针)()
			(this->*消息处理函数指针)()
		})
	}
	//在外部调用时
	类名 Classobject();
	Classobject.想封装的创建窗口函数( &类名::具体的创建窗口函数1 , &类名::消息处理要运行的函数1 );

——这样就完成了这个函数的封装

4.新的问题————————————————————————————————————————


但是在调用时候我很快发现了问题 就是这个方法中 消息处理函数有可能不只执行一种
就是:

	void 想封装的创建窗口函数(???){
		thread 创建线程({
			具体的创建窗口函数?();
			消息处理要运行的函数1(); //消息处理可能调用多个
			消息处理要运行的函数3();
			消息处理要运行的函数4();
			消息处理要运行的函数8();
		});
	}

如果按照之前的函数指针写 就只能调用一个消息处理函数。
所以还要进行进一步调整
最后选择使用 可变参数 来传入不定数量的函数指针 这样就可以在函数体内部调用任意数量的处理函数

5.最终方案————————————————————————————————————————


使用 initializer_list <type> 来实现 可变参数 (具体参考-> 微软文档 WIndowsLearn :省略号和可变参数模板
传入的参数可以使用 迭代器进行遍历 ,然后直接调用就可以了 (文中直接进行了遍历)

	void 想封装的创建窗口函数(void (类名::*创建窗口函数指针)() , initializer_list<void (类名::*)()> 消息处理函数列表){
		thread 创建线程({
			具体的创建窗口函数?();
			for(auto 消息处理函数 : 消息处理函数列表 ){
				(this->*消息处理函数)();
			}
		});
	}
	//在外部调用时
	类名 Classobject();
	Classobject.想封装的创建窗口函数( &类名::具体的创建窗口函数1 , 
		{ &类名::消息处理要运行的函数1 , &类名::消息处理要运行的函数3 , &类名::消息处理要运行的函数4, &类名::消息处理要运行的函数8 } );

最后贴上我原本的代码

	void CreatWnd(HWND(WindowsControl::* CreatWndFunction)(const WindowStyle&), const WindowStyle& Style, initializer_list<void (WindowsControl::*)()> MessageCallBacklist) {
		thread th([this, CreatWndFunction, MessageCallBacklist, Style] {
				(this->*CreatWndFunction)(Style);
				MessageManager(MessageCallBacklist);
			});
		th.detach();
	}

	void MessageManager(initializer_list<void (WindowsControl::*)()> MessageCallBacklist) {
		MSG msg = { 0 };
		while (msg.message != WM_CLOSE) {
			if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
				DispatchMessage(&msg);
			}
			for (auto i : MessageCallBacklist) {
				(this->*i)();
			}
		}
	}
	//外部调用
	WindowsControl wc("newclasses");
	wc.CreatWnd(&WindowsControl::CreatWndOverLay, WindowStyle("ShadowStars",parentwnd), {&WindowsControl::FollowWindows});

6.总结————————————————————————————————————————


  • 想通过函数指针进行封装
  • 外部传入成员函数指针时 需要使用 &类名::成员函数名
  • 内部调用成员函数指针时 需要使用 this 指针调用
  • 通过 initializer_list <> 来传递可变参数

希望能帮到各位 辛苦点个赞叭 😃

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值