解决C++工程中类之间函数回调问题 (工程中类之间)

解决C++工程中类之间函数回调问题1.0初版

写在前面

本文为了优雅的解决类之间函数回调问题,由于第一次发表原创文章,故存在披露在所难免,有问题大家友好讨论。

开门见山

先上代码,再介绍代码里面的一些知识点及关键点。代码均可完美编译运行,编译运行环境VS2019

main.cpp

#include <iostream>
#include <functional>//函数指针的头文件
#include <string>
#include "ClassA.h"
#include "ClassB.h"
#include "FunCollectSingleton.h"
using namespace std;

ClassA  *pClassA;
ClassB* PClassB;

void BindFunc();

int main(int argc, char* argv[])
{
    //这样进行回调  存在风险  就是函数指针未绑定就进行调用 会导致程序崩溃
    //未绑定的函数指针相当于野指针/空指针
    //所以应该使用接口进行回调可避免这样的问题
    BindFunc();
    std::cout << "在主函数里面 回调/调用  ClassA::Func1" << endl;
    FunCollectSingleton::Instance()->AFunc1();//在主函数里面 回调/调用  ClassA::Func1
    std::cout << "在主函数里面 回调/调用  ClassB::Func1" << endl;
    FunCollectSingleton::Instance()->BFunc1();//在主函数里面 回调/调用  ClassB::Func1
    std::cout << "直接调用" << endl;
    pClassA->Func1();//直接调用
    std::cout << "在类A中 回调/调用 ClassB::Func1" << endl;
    pClassA->CallClassBFunc();//在类A中 回调/调用 ClassB::Func1
    std::cout << "" << endl;
    std::cout << "FunCollectSingleton::Instance()->AFunc2(10): "<< FunCollectSingleton::Instance()->AFunc2(10) <<std::endl;//回调/调用
    return 0;
}

void BindFunc()//绑定
{
    pClassA = new ClassA();
    pClassA->SetObjName("pClassA");
    FunCollectSingleton::Instance()->AFunc1= std::bind(&ClassA::Func1, pClassA);//无参的绑定方式
    FunCollectSingleton::Instance()->AFunc2 = std::bind(&ClassA::Func2, pClassA, std::placeholders::_1);//有参的绑定方式

    PClassB = new ClassB();
    PClassB->SetObjName("PClassB");
    FunCollectSingleton::Instance()->BFunc1 = std::bind(&ClassB::Func1, PClassB);//无参的绑定方式
}

FunCollectSingleton.h

#pragma once
#include <functional>
class FunCollectSingleton
{
public:
    FunCollectSingleton(FunCollectSingleton&) = delete;
    FunCollectSingleton& operator=(const FunCollectSingleton&) = delete;
    static FunCollectSingleton* Instance();
    
public:
    std::function<void()> AFunc1;
    std::function<int(int)> AFunc2;
    //例如:此时要是ClassA中增加一个新方法例如void Func3(int a) 
    //则对于与这里也要同步增加一个函数指针std::function<void(int)> AFunc3;
    //并且绑定的时候依葫芦画瓢即可

    std::function<void()> BFunc1;

private:
    FunCollectSingleton() {};
    static FunCollectSingleton Ins;
};

FunCollectSingleton.cpp

#include "FunCollectSingleton.h"

FunCollectSingleton FunCollectSingleton::Ins;

FunCollectSingleton* FunCollectSingleton::Instance()
{
	return &Ins;
}

ClassA.h

#pragma once
#include <string>
class ClassA
{
public:
	ClassA();
	~ClassA();
public:
	void Func1();
	int Func2(int a);
	//void Func3(int a);
	//此时增加一个方法 void Func3(int a);
	//对应于FunCollectSingleton 类来说 同步增加一个函数指针std::function<void(int)> AFunc3;即可
	//然后绑定调用即可
	void SetObjName(std::string objName);

	void CallClassBFunc();

private:
	std::string ObjName;
};

ClassA.cpp

#include "ClassA.h"
#include <iostream>
#include "FunCollectSingleton.h"

ClassA::ClassA()
{
}

ClassA::~ClassA()
{
}

void ClassA::Func1()
{
	std::cout << "ClassA::Func1"<<"  ObjName:  "<< ObjName << std::endl;
}

int ClassA::Func2(int a)
{
	std::cout << "ClassA::Func2" << "  ObjName:  " << ObjName << std::endl;
	return a+1;
}

void ClassA::SetObjName(std::string objName)
{
	ObjName = objName;
}

void ClassA::CallClassBFunc()
{
	FunCollectSingleton::Instance()->BFunc1();//回调/调用
}

ClassB.h

#pragma once
#include <string>
class ClassB
{
public:
	ClassB();
	~ClassB();
public:
	void Func1();

	void SetObjName(std::string objName);

private:
	std::string ObjName;
};

ClassB.cpp

#include "ClassB.h"
#include <iostream>

ClassB::ClassB()
{
}
ClassB::~ClassB()
{
}
void ClassB::Func1()
{
	std::cout << "ClassB::Func1" << "  ObjName:  " << ObjName << std::endl;
}

void ClassB::SetObjName(std::string objName)
{
	ObjName = objName;
}

介绍

由于代码里面已经有比较完善的注释了,故只介绍代码注释未涉及的部分。

1、

std::function<int(int)> AFunc2;

中的<int(int)>就是函数指针需要变化的部分,例如本例子中<int()>中的int就是需要绑定函数的返回值
而(int)中的int就是需要绑定函数的参数

例如std::function<int(int)> AFunc2;绑定的就是ClassA::Func2即:
FunCollectSingleton::Instance()->AFunc2 = std::bind(&ClassA::Func2, pClassA, std::placeholders::_1);//有参的绑定方式

2、
这里使用单列方式为了保持绑定的函数指针及调用的函数指针是同一份东西,并且方便在任意地方随时访问。

3、倘若有这样的类加载顺序
在这里插入图片描述
由于A类的加载链路上完全找不到D类的任何信息,又要回调D类的方法,且不能更改类加载顺序,故通过此方法可以很有效的解决这一问题,而真实的项目远比这简单示意图复杂的多,故如何优雅且安全方便的回调是有必要的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值