C++高级开发之可调用对象、function、bind(1)

简介: 可调用对象  以前函数调用总是离不开一堆圆括号,没错“()”就是函数调用的一个明显标记,这个 “()”有一个称呼叫函数调用运算符。

可调用对象

       07e2320bb649465785e379d4b78237ed.png                        

以前函数调用总是离不开一堆圆括号,没错“()”就是函数调用的一个明显标记,这个 “()”有一个称呼叫函数调用运算符

那么在类中重载了这个函数调用运算符“()”,就可以像使用函数一样是用那个该类的对象,或者换句话说就可以像函数调用一样来“调用”该类的对象

1.函数指针

  创建一个.cpp文件然后加入以下代码

void myfunc(int tv)
{
  cout << "myfunc()函数执行了,tv=" << tv << endl;
}

 在 main函数中加入如下代码

  void(*pmf)(int) = myfunc;
  pmf(20);

07e2320bb649465785e379d4b78237ed.png

2.具有 operator() 成员函数的类对象(仿函数/函数对象)

  仿函数的定义:仿函数又称为函数对象,是一个能行使函数功能的类所定义的对象。防寒输得语法几乎和普通的函数调用一样。

  在 cpp文件前面增加如下 TC类定义

class TC
{
public:
  void operator()(int tv)
  {
    cout << " TC::operator()执行了,tv=" << tv << endl;
  }
};

 在main函数中加入如下代码(可以选择将之前的main函数注释掉)

  TC tc;
  tc(20);//调用的是()操作符,这就是个可调用对象。等价于tc.operator()(20);


8eea4d9e58ce47c8bb1c8ec6d0438e04.png

3.可被转换为函数指针的类对象

  可被转换为函数值指针的类对象也可以叫做 仿函数或函数对象

  在 cpp文件中增加如下 TC2类定义

class TC2
{
public:
  using tfpoint = void(*)(int);
  static void mtsfunc(int tv) //静态成员函数
  {
    cout << "TC2::mysfunc()静态成员函数执行了,tv=" << tv << endl;
  }
  operator tfpoint() { return myfunc; }//类型转换运算符/类型转换函数
};

在main主函数中,加入如下代码

  TC2 tc2;
  tc2(30);

168fed1804104330a69720b236882a4c.png

4.类成员函数指针

  在前面的 TC类中增加一个 public修饰的成员函数和一个成员变量

public:
  void ptfunc(int tv)
  {
    cout << "TC::ptfunc()执行了,tv=" << tv << endl;
  };
  int m_a;

在 main主函数中加入如下代码

  TC tc3;
  void(TC::*myfpoint)(int) = &TC::ptfunc;//类成员函数指针变量 myfpoint定义并被给初值
  (tc3.*myfpoint)(999); //要调用你成员函数,就必须要用到对象 tc3


109006ea54ba4e5e83f1316c3a8bbb01.png

6.总结

  可调用对象首先被看做一个对象。那么有没有一种方法能够把这些可调用对象的调用形式统一起来呢?有,那就是使用 std::function 把这些可调用对象包装起来。

std::function 可调用对象包装器

 要使用这个类模板,在 cpp文件中要添加头文件 #include

 这个蕾姆办理装的是各种可调用对象,比较遗憾的是不能装类成员函数指针。因为类成员函数指针是需要类对象参与才能完成调用的。

  #include 类模板的特点是:**通过指定模板参数,它能够用统一的方式来处理各种可调用对象。

1.绑定普通函数

  在 main 主函数中加入如下代码

        //返回类型(参数列表)
  std::function<void(int)>f1 = myfunc;//绑定一个普通函数,注意<>中的格式
  f1(100);//调用普通函数


19454a10fef2493ea972dce187629d83.png

2绑定类的静态成员函数

  在前面的TC类中增加一个 public修饰的静态成员函数

  static int stcfunc(int tv)
  {
    cout << "TC::stcfunc()静态函数执行了,tv=" << tv << endl;
    return tv;
  }

在 main函数中加入如下代码

            //返回类型(参数列表)
  std::function<int(int)> fs2 = TC::stcfunc;
  fs2(110);

9770ea6c7f684ed99881c7cfe24196b3.png

3绑定仿函数

  在 main函数中,加入如下代码

  TC tc3;
  std::function<void(int)> f3 = tc3;//提示使用了未初始化的局部变量“tc3”,因为类TC里有成员变量没被初始化,需要增加一个构造函数,还应该初始化一下成员变量才好

35fcf8ed32cf404c9b9d8b2964ebade6.png

  在 TC类中增加 public修饰的构造函数并初始化成员变量 m_a

TC()  //构造函数
  {
    m_a = 1;
  }//加入之后不会再报错了

在 main主函数中,继续增加代码

  f3(120); //TC::operator()执行了, tv = 120
  TC2 tc4;
  std::function<void(int)> f4 = tc4;
  f4(150); //TC2::mysfunc()静态成员函数执行了, tv = 150

11f51b8724f244db985c0146b032ba7a.png

4范例演示

在 cpp文件 前面增加如下 CB类和 CT类定义

class CB
{
  std::function<void()> fcallback;
public:
  CB(const std::function<void()>& f) :fcallback(f)
  {
    int i;
    i = 1;
  }
  void runcallback(void)
  {
    fcallback();
  }
};
class CT
{
public: 
  CT()//构造函数
  {
    cout << "CT::CT()执行" << endl;
  }
  CT(const CT&)//拷贝构造函数
  {
    cout << "CT::CT(const CT&)执行" << endl;
  }
  ~CT()
  {
    cout << "CT::~CT()执行" << endl;
  }
  void operator()(void)
  {
    cout << "CT::opertor()执行" << endl;
  }
};

在 main函数中,加入如下代码:

  CT ct; //可调用对象,这行导致CT构造函数的执行
  CB cb(ct); //cb需要可调用对象做参数来构造,ct因为有operator()所以可以转为const std::function<void (void)> &对象。
           //这行导致CT拷贝构造函数被执行多次
  cb.runcallback(); //CT::opertor()执行

dcf5832e23ed4bf882bb50b29f1a24c0.png

再来一个范例,在 cpp前面增加如下代码

void mycallback(int cs, const std::function<void(int)>& f)
{
  f(cs);
}
void runfunc(int x)
{
  cout << x << endl;
}

在 main中函数中,加入如下代码:

    for (int i = 0; i < 10; i++)
    {
      mycallback(i, runfunc);//0,1,2,3,4,5,6,7,8,9
    }

a56c02d94b9f4222a61853b09af5e7c8.png

从范例中可以看出 std::function 的灵活性非常高,能容纳的可调用对象种类也非常多。

C++高级开发之可调用对象、function、bind(2)https://developer.aliyun.com/article/1415895?spm=a2c6h.13148508.setting.24.16254f0exsfwiz

目录
打赏
0
0
0
0
4
分享
相关文章
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
083_类_对象_成员方法_method_函数_function_isinstance
本内容主要讲解Python中的数据类型与面向对象基础。回顾了变量类型(如字符串`str`和整型`int`)及其相互转换,探讨了加法在不同类型中的表现。通过超市商品分类比喻,引出“类型”概念,并深入解析类(class)与对象(object)的关系,例如具体橘子是橘子类的实例。还介绍了`isinstance`函数判断类型、`type`与`help`探索类型属性,以及`str`和`int`的不同方法。最终总结类是抽象类型,对象是其实例,不同类型的对象有独特运算和方法,为后续学习埋下伏笔。
83 7
083_类_对象_成员方法_method_函数_function_isinstance
[oeasy]python083_类_对象_成员方法_method_函数_function_isinstance
本文介绍了Python中类、对象、成员方法及函数的概念。通过超市商品分类的例子,形象地解释了“类型”的概念,如整型(int)和字符串(str)是两种不同的数据类型。整型对象支持数字求和,字符串对象支持拼接。使用`isinstance`函数可以判断对象是否属于特定类型,例如判断变量是否为整型。此外,还探讨了面向对象编程(OOP)与面向过程编程的区别,并简要介绍了`type`和`help`函数的用法。最后总结指出,不同类型的对象有不同的运算和方法,如字符串有`find`和`index`方法,而整型没有。更多内容可参考文末提供的蓝桥、GitHub和Gitee链接。
77 11
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
6月前
|
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
151 19
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
179 13
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等