C++成员函数当作参数调用的两种方式

news2025/1/13 15:37:37

     平时编程时,多用来将数据进行传参,在考虑回调场景下我们会将函数单做参数传给被调用函数,让被调用函数在时机成熟时进行调用。在某些场景下,需要将类的成员函数当作参数进行回调,此时定义成员函数形参的方式通常有两种,以一种是成员函数指针类型,另外一种是使用std::function函数包装器。

目录

1. C++常见的可调用对象

(1) 普通函数

(2) lambda表达式

(3) 函数对象类

(4) 类的静态成员函数

(5) 类的普通成员函数

2. 成员函数指针当作形参调用成员函数

3. std::function作为形参调用成员函数


1. C++常见的可调用对象

(1) 普通函数

int MyAdd(int num1, int num2){ return num1+num2; }

(2) lambda表达式

auto MyMod = [](int num1, int num2){ return num1%num2; };

(3) 函数对象类

struct MyDivide{
    int operator()(int num1, int num2){
        return num1/num2;
    }
};

(4) 类的静态成员函数

class MyMul {
public:
    static int mul(int num1, int num2) {
        return num1*num2;
    }
};

(5) 类的普通成员函数

class MyClass {
public:
    void show(const int &num1 = 100, const int &num2 = 300) {
        std::cout << num1 << " +-*/ " << num2 << std::endl;
    }
};

调用方式:

void testCanCallFunc() {
    std::function<int(int, int)>  a = MyAdd; 
    std::function<int(int, int)>  b = MyMod; 
    std::function<int(int, int)>  c = MyDivide();
    std::function<int(int, int)>  d = MyMul::mul;
    MyClass myClass;
    std::function<void(const int&, const int&)>  e = std::bind(&MyClass::show, &myClass, std::placeholders::_1, 9527);
    std::function<void(const int&, const int&)>  f = std::bind(&MyClass::show, &myClass, std::placeholders::_1, std::placeholders::_2);

    std::cout << a(111, 222) << std::endl;
    std::cout << b(100, 200) << std::endl;
    std::cout << c(200, 300) << std::endl;
    std::cout << d(777, 888) << std::endl;
    e(1, 2);
    f(4, 5);

    auto fun1 = [] (int a1, int a2) {
    std::cout << a1 << "  " << a2 << std::endl;
    };

    auto myFun = [a, b, c, fun1](int a1, int a2){
        std::cout << a(a1, a2) << std::endl;
        std::cout << b(a1, a2) << std::endl;
        std::cout << c(a1, a2) << std::endl;
        fun1(a1, a2);
    };
    myFun(111, 333);
}

调用结果:

2. 成员函数指针当作形参调用成员函数

如下定义两个类:

class TestClass1 {
public:
  TestClass1() {}
  ~TestClass1() {}
  void fun() { std::cout << __FUNCTION__ << std::endl; }
  void fun1() { std::cout << __FUNCTION__ << std::endl; }
private:

};

class TestClass2 {
public:
  TestClass2() {}
  ~TestClass2() {}
  void fun() { std::cout << __FUNCTION__ << std::endl; }
  void fun1() { std::cout << __FUNCTION__ << std::endl; }
  void fun2(const int& num) { std::cout << __FUNCTION__ << " " << num << std::endl; }
private:

};

调用其成员函数:

//成员函数指针形式参数,此处abxd和exf是形参数名字,可以随便起名字
void CallMemberFun(TestClass1& t1, void (TestClass1::*abxd)(), 
                    TestClass2 t2, void (TestClass2::*exf)(),
                    void (TestClass2::*hello)(const int &a), 
                    const int& num = 1234) {
  (t1.*abxd)();
  (t2.*exf)();
  (t2.*hello)(num);
}

void testUseClassMemFunc() {
  TestClass1 t1 = TestClass1();
  CallMemberFun(t1, &TestClass1::fun1, TestClass2(), 
                      &TestClass2::fun, 
                      &TestClass2::fun2);
}

调用结果:

3. std::function作为形参调用成员函数

//std::function充当形式参数,通过std::bind转换成员函数为std::function类型,来实现对成员函数的调用
void CallMemberFun(std::function<void()> abxd, 
                    std::function<void()>exf,
                    std::function<void(const int&)> hello, 
                    const int& num = 1234) {
  abxd();
  exf();
  hello(num);
}

void testUseClassMemUseFunciton() {
  TestClass1 t1 = TestClass1();
  auto aFun = std::bind(&TestClass1::fun1, &t1);
  TestClass2 t2 = TestClass2(); 
  auto aFun2 = std::bind(&TestClass2::fun2, &t2, std::placeholders::_1);
  CallMemberFun(aFun, std::bind(&TestClass1::fun1, &t1), aFun2, 7788); 
}

调用结果如下:

附录:

完整代码:

#include <iostream>
#include <functional>

//普通函数
int MyAdd(int num1, int num2){ return num1+num2; } 

//lambda表达式
auto MyMod = [](int num1, int num2){ return num1%num2; };

//函数对象类
struct MyDivide{
    int operator()(int num1, int num2){
        return num1/num2;
    }
};

//类的静态成员函数
class MyMul {
public:
static int mul(int num1, int num2) {
    return num1*num2;
    }
};

//普通类的成员函数
class MyClass {
public:
    void show(const int &num1 = 100, const int &num2 = 300) {
        std::cout << num1 << " +-*/ " << num2 << std::endl;
    }
};

class TestClass1 {
public:
  TestClass1() {}
  ~TestClass1() {}
  void fun() { std::cout << __FUNCTION__ << std::endl; }
  void fun1() { std::cout << __FUNCTION__ << std::endl; }
private:

};

class TestClass2 {
public:
  TestClass2() {}
  ~TestClass2() {}
  void fun() { std::cout << __FUNCTION__ << std::endl; }
  void fun1() { std::cout << __FUNCTION__ << std::endl; }
  void fun2(const int& num) { std::cout << __FUNCTION__ << " " << num << std::endl; }
private:

};

//成员函数指针形式参数,此处abxd和exf是形参数名字,可以随便起名字
void CallMemberFun(TestClass1& t1, void (TestClass1::*abxd)(), 
                    TestClass2 t2, void (TestClass2::*exf)(),
                    void (TestClass2::*hello)(const int &a), 
                    const int& num = 1234) {
  (t1.*abxd)();
  (t2.*exf)();
  (t2.*hello)(num);
}


//std::function充当形式参数,通过std::bind转换成员函数为std::function类型,来实现对成员函数的调用
void CallMemberFun(std::function<void()> abxd, 
                    std::function<void()>exf,
                    std::function<void(const int&)> hello, 
                    const int& num = 1234) {
  abxd();
  exf();
  hello(num);
}

void testCanCallFunc() {
    std::function<int(int, int)>  a = MyAdd; 
    std::function<int(int, int)>  b = MyMod; 
    std::function<int(int, int)>  c = MyDivide();
    std::function<int(int, int)>  d = MyMul::mul;
    MyClass myClass;
    std::function<void(const int&, const int&)>  e = std::bind(&MyClass::show, &myClass, std::placeholders::_1, 9527);
    std::function<void(const int&, const int&)>  f = std::bind(&MyClass::show, &myClass, std::placeholders::_1, std::placeholders::_2);

    std::cout << a(111, 222) << std::endl;
    std::cout << b(100, 200) << std::endl;
    std::cout << c(200, 300) << std::endl;
    std::cout << d(777, 888) << std::endl;
    e(1, 2);
    f(4, 5);

    auto fun1 = [] (int a1, int a2) {
    std::cout << a1 << "  " << a2 << std::endl;
    };

    auto myFun = [a, b, c, fun1](int a1, int a2){
        std::cout << a(a1, a2) << std::endl;
        std::cout << b(a1, a2) << std::endl;
        std::cout << c(a1, a2) << std::endl;
        fun1(a1, a2);
    };
    myFun(111, 333);
}

void testUseClassMemFunc() {
  TestClass1 t1 = TestClass1();
  CallMemberFun(t1, &TestClass1::fun1, TestClass2(), 
                      &TestClass2::fun, 
                      &TestClass2::fun2);
}

void testUseClassMemUseFunciton() {
  TestClass1 t1 = TestClass1();
  auto aFun = std::bind(&TestClass1::fun1, &t1);
  TestClass2 t2 = TestClass2(); 
  auto aFun2 = std::bind(&TestClass2::fun2, &t2, std::placeholders::_1);
  CallMemberFun(aFun, std::bind(&TestClass1::fun1, &t1), aFun2, 7788); 
}

int main(int argc, char *argv[]) {
    testCanCallFunc();
    std::cout << "===================================" << std::endl;
    testUseClassMemFunc();
    std::cout << "===================================" << std::endl;
    testUseClassMemUseFunciton();
	return 0;
}

运行结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/110219.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我的python学习经历及资源整理

对于小白来说&#xff0c;有个人引导会比自学要高效的多&#xff0c;尤其容易坚持不下去的小伙伴。可以试试下面这个入门课程&#xff0c;不用本地安装Python环境&#xff0c;能直接在网页上敲代码&#xff0c;还有大牛老师带着入门&#xff0c;能少走很多弯路&#xff01;只要…

直播弹幕系统(五)- 整合Stomp替换原生WebSocket方案探究

直播弹幕系统&#xff08;五&#xff09;- 整合Stomp替换原生WebSocket方案探究前言一. STOMP 协议简单介绍1.1 客户端编码基础1.2 服务端编码基础1.2.1 SimpMessagingTemplate1.2.2 SendTo 和 MessageMapping二. SpringBoot整合STOMP并实现聊天室2.1 基础配置和依赖2.2 WebSoc…

华为EC6108V9C免拆卡刷固件包

华为EC6108V9C免拆卡刷固件包 固件特点&#xff1a; 1、修改dns&#xff0c;三网通用&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、无开机广告&#xff0c;无系统更新&#xff0c;不在被强制升级&#xff1b; 4、大量精简内置的没用的软件&…

Redis高级篇之最佳实践

Redis高级篇之最佳实践 本章内容 Redis 键值设计批处理优化服务端优化集群最佳实践 笔记整理自 b站_黑马程序员Redis入门到实战教程 1. Redis键值设计 优雅的key结构 Redis 的 Key 虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&a…

Docker容器中安装Jenkins

众所周知,jenkins是现在比较流行的一种工具,今天就记录一下在工作中如何使用了jenkins&#xff0c; 由于我使用的使用Linux(Debain 11)开发环境使用了jdk1.8&#xff0c;会跟最新版的jenkins(官方介绍最新版要jdk11支持)有不良的化学反应&#xff0c;所以把jenkins放到了容器中…

Hive+Spark离线数仓工业项目实战--项目介绍及环境构建(2)

Docker的介绍 了解Docker的基本功能和设计 - 为什么要用Docker&#xff1f; - 什么是Docker&#xff1f; 路径 - step1&#xff1a;生产环境的问题 - step2&#xff1a;容器的概念 - step3&#xff1a;Docker的设计 实施 生产环境的问题 - 运维层面&#xff1a;一…

Windows下的通用进程守护程序(持续更新中),高仿supervisor。

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;无尽的折腾后&#xff0c;终于又回到…

【Three.js入门】标准网格材质、置换贴图、粗糙度贴图、金属贴图、法线贴图

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

【实时数仓】DWS层的定位、DWS层之访客主题计算(PV、UV、跳出次数、计入页面数、连续访问时长)

文章目录一 DWS层与DWM层的设计1 设计思路2 需求梳理3 DWS层定位二 DWS层-访客主题计算1 需求分析与思路2 功能实现&#xff08;1&#xff09;封装VisitorStatsApp&#xff0c;读取Kafka各个流数据a 代码b 测试&#xff08;2&#xff09;合并数据流a 封装主题宽表实体类Visitor…

CMakeList

目录 .1 简介 .2 常用命令 2.1 指定 cmake 的最小版本 2.2 设置项目名称 2.3 设置编译类型 2.4 指定编译包含的源文件 2.4.1 明确指定包含哪些源文件 2.4.2 搜索所有的 cpp 文件 2.4.3自定义搜索规则 2.5 查找指定的库文件 2.6. 设置包含的目录 2.7. 设置链接库搜索…

中国晶振市场规模将增长至2026年的263.21亿元,国产市场未来可期

晶振作为频率控制和频率选择基础元件&#xff0c;广泛应用于资讯设备、移动终端、通信及网络设备、汽车电子、智能电表、电子银行口令卡等领域&#xff0c;随着新兴电子产业、物联网的快速发展&#xff0c;及以 5G、蓝牙 5.0、Wi-Fi 6 等无线通信新技术的广泛应用&#xff0c;预…

基于Python的Flask WEB框架实现后台权限管理系统(含数据库),内容包含:用户管理、角色管理、资源管理和机构管理

#基于Flask实现后台权限管理系统 重磅&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 全新的风格界面&#xff0c;完全的前后端分离。基于ElementUI&#xff0c;前端代码基于RuoYi…

plotly parallel_coordinates平行坐标可视化

使用plotly画平行坐标图&#xff0c;代码如下&#xff1a; 其中数据使用excel的csv格式&#xff08;当然可以使用其它格式&#xff09;&#xff0c;csv的标头是参数名。 import plotly.express as px import numpy as np import pandas as pd# df px.data.iris() df pd.read…

【爬虫】JS逆向解决反爬问题系列3—sign破解

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…

DOM(一):获取页面元素、操作元素

DOM&#xff08;一&#xff09;获取页面元素事件操作元素获取页面元素 1.根据ID获取 使用getElementById()方法获取带有ID的元素对象,格式如下&#xff1a; var 变量名 document.getElementById(‘id名’); 例如&#xff1a; <div id time>2022-12-18</div> &…

PyTorch——应用一个已训练好的图片分类网络——AlexNet

1.识别一个图像主体的预训练网络 ImageNet数据集是由一个Stanford大学维护的包含1400多万幅图像的非常大的数据集&#xff0c;所有的图像都用来自WordNet数据集的名词层次结构标记&#xff0c;而WordNet数据集又是一个大型的英语词汇数据库。 1.1获取一个预先训练好的网络用于…

【矩阵论】7.范数理论——基本概念——矩阵范数生成向量范数谱范不等式

7.1.3 矩阵范数产生向量范数 CnnC^{n\times n}Cnn 上任一矩阵范数 ∥∙∥\Vert \bullet\Vert∥∙∥ 都产生一个向量范数 φ(X)∥X∥V\varphi(X)\Vert X\Vert_Vφ(X)∥X∥V​ 矩阵范数与向量范数的相容性&#xff1a;φ(Ax)≤∥A∥φ(x)\varphi(Ax)\le \Vert A\Vert\varphi(x)φ…

蓝牙耳机什么牌子好?音质好、配置高的蓝牙耳机分享

​经常听到很多网友在讨论哪些蓝牙耳机好用&#xff0c;什么蓝牙耳机的配置高......选购蓝牙耳机无非就是音质、蓝牙技术、续航、佩戴体验等各方面条件&#xff0c;还有哪位朋友不知道该如何选购蓝牙耳机的&#xff1f;根据我对蓝牙耳机的了解&#xff0c;从网上整理了好几款蓝…

【关于eps8266自动重启 Soft WDT reset】

【关于eps8266自动重启 Soft WDT reset】1. 前言2. 分析问题2.1 长时间没有喂狗2.2 delayMicroseconds 函数触发3. 解决问题3.1 解决长时间没有喂狗3.2 解决delayMicroseconds 函数触发5. 小结1. 前言 最近使用esp8266进行远程遥控时, 但是在驱动舵机servo库的过程中出现了esp…

第二证券|两大板块掀涨停潮,有个股猛拉20cm!这只港股复牌一度暴跌

A股商场周五上午窄幅震动&#xff0c;上证指数微涨0.09点&#xff0c;核算机等板块领涨。 新股体现持续分解&#xff0c;4只今日上市的新股中&#xff0c;两只科创板新股上涨&#xff0c;两只北交所新股则破发。 港股全体小幅调整&#xff0c;全体动摇不算大&#xff0c;但仍…