iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++11 成员函数作为回调函数的使用方式
  • 117
分享到

C++11 成员函数作为回调函数的使用方式

C++11 成员函数C++11 回调函数使用回调函数 2022-11-13 19:11:37 117人浏览 薄情痞子
摘要

目录c++11成员函数作为回调函数使用示例1示例2类成员函数作为回调函数的方法及注意点类成员函数当回调函数的方法为什么回调函数必须为静态函数?类的静态成员函数如何访问非静态成员?C+

C++11成员函数作为回调函数使用

std::bind()被广泛地应用在新式的回调函数中。

C++11以前类的普通成员函数不能作为回调函数去注册,因为将普通成员函数注册给对方,但对方使用这个函数指针时,就会发生参数列表匹配的问题,因为少了隐含的this。

静态成员函数不包含this指针,所以一般将静态成员函数注册给对方。

C++11推出std::bind()和std::function搭配,前者生成新的调用对象,参数个数可以小于绑定函数的参数个数,少的参数,按位占用。后者保存函数调用类型的函数对象,使用该对象进行设置参数即可。

示例1

先看一个例子来热热身,熟悉一下std::bind和std::function

#include <functional> //所需std::bind和std::function头文件
#include <iOStream>
#include <map>

using namespace std;
// 使用std::bind时记得和::bind区别开,就怕作用于污染,误用::bind

//除法运算
class Division {
public:
    int operator()(int i, int j) { return i / j; }
};

//乘法运算
int Multiplication(int i, int j) { return i * j; }

//减法运算
int Substraction(int i, int j) { return i - j; }

//回调注册函数
int CallbackReg(function<int(int, int)> &func, int i, int j) { return func(i, j); }

//回调注册函数1,
int CallbackReq1(function<int(int)> &&func, int i) { return func(i); }

int main() {

    // 此function接受函数调用类型为int(int, int)的调用对象
    function<int(int, int)> func1 = [](int i, int j) { return i + j; }; //lambda
    function<int(int, int)> func2 = &Substraction;                        //函数指针
    function<int(int, int)> func3 = Multiplication;                        //函数名
    function<int(int, int)> func4 = Division();                            //重载调用运算符的对象

    //可将function类型存在容器中,来一次映射
    map<int, function<int(int, int)>> mpFuncs;
    mpFuncs[1] = func1;
    mpFuncs[2] = func2;
    mpFuncs[3] = func3;
    mpFuncs[4] = func4;

    //这里做着玩,映射一个数字和字符串
    map<int, string> mpOprs{{1, " + "}, {2, " - "}, {3, " * "}, {4, " / "}};

    // 便利map调用容器内函数对象们
    for (auto& it : mpFuncs) {
        cout << "calculator :" << 20 << mpOprs[it.first] << 5 
            << " = " << CallbackReg(it.second, 20, 5) << endl;
    }

    //使用std::bind,产生一个新的调用对象bindFunc(int i), 200作为int Multiplication(int i, 200)
    //std::placeholders 有个N个占位符(vs此版为20个):_N,表示占用绑定函数的第n个位子
    int pre = 300;
    auto bindFunc = std::bind(Multiplication, placeholders::_1, pre);
    cout << bindFunc(3) << endl;

    //bind最重要的一点在于参数绑定,如下例注册回调,参数就从2个变成了1个
    cout << CallbackReq1(std::bind(Multiplication, placeholders::_1, 200), 2) << endl;

    return 0;

}

calculator :20 + 5 = 25
calculator :20 - 5 = 15
calculator :20 * 5 = 100
calculator :20 / 5 = 4
900
400

好,在了解了std::bind和std::function之后来看一个平时常遇到的C++式的回调函数注册

示例2

#include <functional>
#include <iostream>
#include <string>
#include <memory>

using namespace std;
using namespace std::placeholders; //占位符_N所在的命名空间

using CallBackFuncType = function<void(string const&)>; 

class Client {
public:
    string name;
    CallBackFuncType serverFunc;

    Client() :name("VerGo"), serverFunc(nullptr) {}
    ~Client() {}

    void SetCallBack(const CallBackFuncType &func) { serverFunc = func; }
    void DoCallBack() { serverFunc(name); }
};

class Server {
public:
    Client *m_clt;
    Server() : m_clt(nullptr) { m_clt = new Client; }
    ~Server() { if (m_clt) delete m_clt; m_clt = nullptr; }

    //回调函数本数
    void MyCallBackFunc(string const& str) { cout << "The name of client is " << str << endl; }
    //注册回调,将this指针绑定到回调函数中
    void ReGCallBackFunc() { if (!m_clt) return;  m_clt->SetCallBack(CallBackFuncType(std::bind(&Server::MyCallBackFunc, this, _1))); }
    //回调
    void GiveMeCallBack() { if (!m_clt) return; m_clt->DoCallBack(); }
};


int main() {

    Server testClass;
    testClass.RegCallBackFunc();
    testClass.GiveMeCallBack();    

    return 0;
}

The name of client is Vergo

类成员函数作为回调函数的方法及注意点

编程中遇到一个错误,提示为error C2597: illegal reference to non-static member

即因为一个类的静态成员函数调用了类的非静态成员变量,而报错。

下面具体介绍一些相关知识点,以防下次再出错。

类成员函数当回调函数的方法

方法一:回调函数为普通的全局函数,但在函数体内执行类的成员函数

在创建线程调用回调函数时,传入类对象的指针(比如this指针)作为参数,并在回调函数中把void*强制转换为类的指针(MyClass*),就能使用该指针调用类的成员函数。

这样做的原理是把当前对象的指针当作参数先交给一个外部函数,再由外部函数调用类成员函数。以外部函数作为回调函数,但执行的是成员函数的功能,这样相当于在中间作了一层转换。

缺点:回调函数在类外,影响了封装性。

方法二:回调函数为类内静态成员函数,在其内部调用类的非静态成员函数

此时需要一个指向类本身的、类的静态成员变量指针(static MyClass* CurMy),用来存储当前回调函数调用的对象,相当于法1中给回调函数传入的指针参数。在回调函数中通过CurMy指针调用类的成员函数。

优点:

  • 1、解决了法1的封装性问题
  • 2、没有占用callback的参数,可以从外界传递参数进来

缺点:每个对象启动子线程前一定要注意先让CurMy正确的指向自身,否则将为其它对象开启线程。

方法三:对成员函数进行强制转换,使其作为回调函数

这个方法是原理是,MyClass::func最终会转化成 void func(MyClass *this);即在原第一个参数前插入指向对象本身的this指针。可以利用这个特性写一个非静态类成员方法来直接作为线程回调函数。

typedef void* (*FUNC)(void*);
FUNC callback = (FUNC)&MyClass::func;

对编译器而言,void (MyClass::*FUNC1)()和void* (*FUNC)(void*)这两种函数指针虽然看上去很不一样,但他们的最终形式是相同的,因此就可以把成员函数指针强制转换成普通函数的指针来当作回调函数。在建立线程时要把当前对象的指针this当作参数传给回调函数(成员函数func),这样才能知道线程是针对哪个对象建立的。

注意:此方法中FUNC函数的参数一定要是void*,这样才能在编译后把this指针转变为MyClass *this。

优点:法3的封装性比法2更好,因为不涉及多个对象共用一个静态成员的问题,每个对象可以独立地启动自己的线程而不影响其它对象。

为什么回调函数必须为静态函数?

普通的C++成员函数都隐含了一个“this”指针参数,当在类的非静态成员函数中访问类的非静态成员时,C++编译器通过传递一个指向对象本身的指针给其成员函数,从而能够访问类的数据成员。也就是说,即使你没有写上this指针,编译器在编译的时候自动加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。

正是由于this指针的作用,使得将一个CALLBACK型的成员函数作为回调函数时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数匹配失败。所以为了实现回调,类中的成员函数必须舍弃掉隐藏的this指针参数。因此,类中的回调函数必须为静态函数,加上static关键字。

类的静态成员函数如何访问非静态成员?

静态成员不属于某个具体的对象,而是被所有对象所共享。即静态成员属于整个类,不属于具体某个对象;非静态成员属于具体某个对象。因而静态成员函数只能访问类的静态成员,不能访问类中非静态成员。

那么,如何让静态函数访问类的非静态成员?

方法是:对于静态成员函数,我们显示的为其传递一个对象的首地址(该类的指针)。一般在这个静态成员函数的形参列表中加入一个  void*  类型的参数,来保存对象的首地址。并在该函数内部对该参数进行类型转换,通过类型转换后的参数来调用非静态成员。

或者用一个类的全局指针数组,保存每一个创建出来的类的this指针,用全局指针去调用。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: C++11 成员函数作为回调函数的使用方式

本文链接: https://www.lsjlt.com/news/170799.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++11 成员函数作为回调函数的使用方式
    目录C++11成员函数作为回调函数使用示例1示例2类成员函数作为回调函数的方法及注意点类成员函数当回调函数的方法为什么回调函数必须为静态函数?类的静态成员函数如何访问非静态成员?C+...
    99+
    2022-11-13
    C++11 成员函数 C++11 回调函数 使用回调函数
  • C/C++ 引用作为函数的返回值方式
    目录case1:用返回值方式调用函数case2:用函数的返回值初始化引用的方式调用函数case3:用返回引用的方式调用函数case4:用函数返回的引用作为新引用的初始化值的方式来调用...
    99+
    2022-11-13
  • C++11lambda表达式在回调函数中的使用方式
    目录一、lambda表达式在C++异步框架中的应用二、如何在C-style注册回调函数中使用lambda表达式?在回调函数中使用lambda表达式的好处,在于可以利用C++的RAII...
    99+
    2022-11-13
    C++11 lambda表达式 使用回调函数 C++11 lambda
  • python中以函数作为参数(回调函数)的实现方法
    目录python以函数作为参数(回调函数)python函数的参数类型一、必须参数二、关键字参数三、默认参数四、不定长参数总结python以函数作为参数(回调函数) 纯粹是自己学习总结...
    99+
    2023-01-04
    python函数 python函数为参数 python回调函数
  • C++中的成员函数和友元函数怎么使用
    成员函数是定义在类中的函数,它可以访问类中的成员变量和其他成员函数。成员函数使用类的对象来调用,并且隐式地访问该对象的成员。友元函数...
    99+
    2023-08-16
    C++
  • C++成员函数中const的使用详解
    目录修饰入参值传递址传递const修饰入参修饰返回值修饰函数总结const 在C++中是一个很重要的关键字,其不光可以用来修饰变量,还可以放在函数定义中,这里整理了其在函数中的三个用...
    99+
    2022-11-13
  • C++中成员函数和友元函数的使用及区别详解
    为什么使用成员函数和友元函数 这个问题至关重要,直接影响着后面的理解: 程序数据: 数据是程序的信息,会受到程序函数的影响。封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一...
    99+
    2022-11-13
  • c++函数调用的方式有哪些
    C++函数可以通过以下方式调用:1. 直接调用:使用函数名、参数列表和分号来调用函数。2. 函数指针调用:将函数的地址保存在指针变量...
    99+
    2023-08-18
    c++
  • C++分析类的对象作类成员调用构造与析构函数及静态成员
    目录类对象作为成员静态成员定义和分类静态成员变量静态成员函数总结类对象作为成员 C++类中的成员可以是另一个类的对象,我们称该成员为 对象成员 例如: class Phone {} ...
    99+
    2022-11-13
  • C语言的回调函数怎么使用
    本篇内容主要讲解“C语言的回调函数怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言的回调函数怎么使用”吧!对指针的应用是C语言编程的精髓所在,而回调函数就是C语言里面对函数指针的高级...
    99+
    2023-06-17
  • C语言的回调函数如何使用
    这篇“C语言的回调函数如何使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言的回调函数如何使用”文章吧。1.程序架构一...
    99+
    2023-06-29
  • C和C++的函数调用方式是什么
    这篇文章主要介绍C和C++的函数调用方式是什么,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!调用方式C/C++函数有多种调用约定。C语言:__cdecl__stdcall__fastcallnaked__pascal...
    99+
    2023-06-29
  • c语言中回调函数的使用方法及作用是什么
    本篇内容介绍了“c语言中回调函数的使用方法及作用是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录前言一、通过这节课程你能掌握以下知识...
    99+
    2023-06-20
  • C++类的对象作类成员调用构造、析构函数及静态成员实例分析
    这篇文章主要介绍了C++类的对象作类成员调用构造、析构函数及静态成员实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++类的对象作类成员调用构造、析构函数及静态成员实例分析文章都会有所收获,下面我们一起...
    99+
    2023-06-30
  • C++中有哪些函数调用的方式
    这篇文章将为大家详细讲解有关C++中有哪些函数调用的方式,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。stdcall很多时候被称为pascal调用约定,因为pascal是早期很常见的一种教学...
    99+
    2023-06-17
  • c语言中的回调函数怎么使用
    这篇文章主要讲解了“c语言中的回调函数怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“c语言中的回调函数怎么使用”吧!一、通过这节课程你能掌握以下知识...
    99+
    2022-10-19
  • C语言中回调函数的使用详情
    目录1.程序架构2.回调函数的作用3.掌握回调函数的程序编写4.回调函数在产品中的应用下文将学习到; 程序架构的核心理念和需求掌握回调函数的作用掌握回调函数的程序编写掌握回调函数在产...
    99+
    2022-11-13
  • c语言中回调函数的使用以及实际作用详析
    目录前言一、通过这节课程你能掌握以下知识:二、程序架构的核心理念和需求三、回调函数的作用1.输出型2.输入型四、掌握回调函数的程序编写总结前言 今天给大家讲一下芯片/模块厂家写SDK...
    99+
    2022-11-12
  • C++分析讲解类的静态成员函数如何使用
    目录一、未完成的需求二、问题分析三、静态成员函数四、小结一、未完成的需求 统计在程序运行期间某个类的对象数目保证程序的安全性(不能使用全局变量)随时可以获取当前对象的数目 在C++分...
    99+
    2022-11-13
  • C++中的string库函数常见函数的作用和使用方法
    目录前言: string库函数是什么正文1.strlen函数是什么具体用法:2.strcpy函数是什么?具体用法3.strcmp函数是什么?具体用法:4.strcat函数是什么?具体...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作