C++使用模板、函数指针、接口和lambda表达式这四种方法做回调函数的区别比较

在C++中,两个类之间存在一种关系,某个类需要另外一个类去完成某一个功能,完成了之后需要告知该类结果,这种最普通最常见的需求,往往使用回调函数来解决。

如题,我总结下来有这么四种方式可以完成这项功能,下面来一一分析:

1、使用模板

// CppTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <math.h>

template<typename T>
class MathTemplate
{
    int ops1,ops2;
    int result;
public:
    void Add(int a,int b,T callback)
    {
        ops1 = abs(a);   /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
        ops2 = abs(b);

        result = ops1+ops2;

        callback.showResult(result);
    }
};

class Result
{
public:
    void showResult(int res)
    {
        printf("result = %d\n",res);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Result reShow;
    MathTemplate<Result> math;
    math.Add(1,3,reShow);

    system("pause");
    return 0;
}

说明:结果类需要知道数学类的处理结果(下面都会使用这个例子),把数学类方法定义为模板函数,回调函数以模板变量的形式传递进去。

优点:两个类耦合度低,数学类不需要知道结果类,结果类因为需要数学类处理,肯定要包括数学类。

缺点:写数学类时,必须要知道结果类有showResult这个方法。

2、使用函数指针

// CppTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <math.h>

class Result;

typedef void (Result::*CallbackPtr)(int);

class MathCallBack
{
    int ops1,ops2;
    int result;
public:
    void Add(int a,int b,Result *caller,CallbackPtr callback)
    {
        ops1 = abs(a);   /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
        ops2 = abs(b);

        result = ops1+ops2;

        (caller->*callback)(result);
    }
};

class Result
{
public:
    void showResult(int res)
    {
        printf("result = %d\n",res);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Result reShow;
    MathCallBack math;

    math.Add(1,3,&reShow,&Result::showResult);

    system("pause");

    return 0;
}

说明:跟上面一样,结果类需要知道数学类的处理结果,主要注意的是C++函数指针的写法与调用,必须以(对象.*函数指针)(参数)的形式调用。所以,传递回调函数时需要传入调用对象。

缺点:这种方法用起来没有优点,直接说缺点,耦合度高,数学类需要直接知道结果类,数学类不能重用,调用方式写起来也是别扭。

3、使用接口

// CppTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <math.h>

class Result;

class IProcessResult
{
public:
    virtual void ProcessResult(int result)=0;
};

class MathCallBack
{
    int ops1,ops2;
    int result;
public:
    void Add(int a,int b,IProcessResult *process)
    {
        ops1 = abs(a);   /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
        ops2 = abs(b);

        result = ops1+ops2;

        process->ProcessResult(result);
    }
};

class Result:public IProcessResult
{
public:
    void ProcessResult(int res)
    {
        printf("result = %d\n",res);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Result reShow;
    MathCallBack math;

    math.Add(1,3,&reShow);

    system("pause");

    return 0;
}

说明:功能一模一样,一样以回调的方式显示结果。

优点:典型的面向接口编程,即结果类针对结果处理接口编程,不针对具体编程,降低耦合度。

缺点:程序中多了一个接口类,多了一个文件,不要小看多了一个文件,在大型项目工程里,有非常多的类似类之间关系,这样做会多出很多只有一个接口函数的类。

4、使用lambda表达式

// CppTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <functional>

class MathCallBack
{
    int ops1,ops2;
    int result;

public:
    void Add(int a,int b,std::function<void (int)> func)
    {
        ops1 = abs(a);   /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
        ops2 = abs(b);

        result = ops1+ops2;
        func(result);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    MathCallBack math;

    
    math.Add(1,3,[](int result) -> void {  
            printf("result = %d\n",result); 
        });

    system("pause");

    return 0;
}

说明:功能一模一样,一样以回调的方式显示结果。注意看lambda的回调函数类型哦!

优点:不用多说,整个代码简洁了不知道多少倍,优点无数。

总结:其实写这个博文就是为了学习C++的lambda表达式,在自己的项目中前3中方法都用了,始终感觉耦合度大,代码不简洁。见识过C#中lambda表达式的巨大优势,就知道C++一定能做到。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值