首页 > 其他分享 >函数对象

函数对象

时间:2023-07-10 12:22:47浏览次数:31  
标签:函数 对象 void Tree doStart pthread include

函数对象

定义

定义了operator()的对象就是函数对象。

函数的封装

可以使用std::function对函数(指向函数的指针)、lambda表达式、bind表达式、函数对象、指向成员函数的指针、指向成员变量的指针;

简单示例

#include <functional>
#include <iostream>

int fun(int a)
{
    std::cout << a << std::endl;
    return 0;
}

int main()
{
    std::function<int(int)> func_wrap(fun);

    func_wrap(1);
    return 0;
}

偏函数

Partial Function Application.

偏函数是指固定多元函数的部分参数,得到一个接受部分参数的函数的转换过程;

std::bind用来实现偏函数;

这是什么

在 C++ 中应该怎么封装一个函数?

C++ 是面向对象的,而函数作为一个地址,本身不是对象;并且类的普通成员函数,不能直接作为一个普通函数去使用(其名字本身不是一个函数指针)。

C++ 是利用仿函数来达到函数封装函数的目的的。仿函数能够像函数那样使用,同时仿函数本身是一个对象,能够携带一些附加参数。

附 1:调用一个对象的成员函数有哪些方式

#include <iostream>

class Tree
{
public:
    void start()
    {
        print ();
    }
private:
    void print()
    {
        std::cout << "print" << std::endl;
    }
};

int main ()
{
    Tree tree;
    tree.start ();
}

通过对象直接调用这个函数,是最常见的方法。

那么是否和普通的函数一样,能够通过函数指针去调用成员函数呢?

以一个例子说明这个问题

pthread 要求传入一个函数指针,例如:

void *func(void *)
{
    // blank
}

int main()
{
    pthread_t tid;
    pthread_create (& tid, NULL, func, NULL);
    return 0;
}

但是 C++ 的实际场景中,更多的函数是以类的成员函数的形式出现的。类的成员函数,仍然是一个函数,但是其名字不能直接作为普通函数使用,因为其隐含了 this 指针。

#include <pthread.h>
#include <stdio.h>

class Tree
{
public:
    void start()
    {
        pthread_t tid;
        pthread_create (& tid, NULL, doStart, NULL);
        return ;
    }
private:
    void *doStart(void *)
    {
        printf ("start\n");
        return NULL;
    }
};

int main()
{
    Tree tree;
    tree.start();
}

这个例子中,在成员函数中直接把成员函数作为函数指针使用,编译会报错

test.cpp: In member function ‘void Tree::start()’:
test.cpp:10:38: error: invalid use of non-static member function ‘void* Tree::doStart(void*)’
   10 |         pthread_create (& tid, NULL, doStart, NULL);
      |                                      ^~~~~~~
test.cpp:14:11: note: declared here
   14 |     void *doStart(void *)
      |           ^~~~~~~

这个例子中,我们需要实现的语义是创建一个线程,这个线程能直接调用类的成员函数。由于成员函数可能是外部不可见的,因此很可能的场景是在类内部创建一个线程,这个线程调用内部的成员函数(和例子中的一样)。

正如提示的那样,我们需要把这个函数变成类的静态成员函数才能直接传给 pthread_create ,但是这样的话就破坏掉了 C++ 的面向对象的形式,譬如静态函数中如果要访问对象的成员,则只能显式的写一个 this 指针参数传递过去,如下:

#include <pthread.h>
#include <stdio.h>

class Tree
{
public:
    void start()
    {
        pthread_t tid;
        pthread_create (& tid, NULL, doStart, this);
        return ;
    }
    void print()
    {
        printf ("hello world\n");
        return ;
    }
private:
    static void *doStart(void *arg)
    {
        Tree *pThis = reinterpret_cast<Tree*>(arg);
        pThis->print();
        return NULL;
    }
};

int main()
{
    Tree tree;
    tree.start();
}

此时编译能够通过,但是破坏了 C++ 的形式(使用了显式的 this 指针)。

一个解决方案

将类的成员函数

#include <functional>
#include <thread>
#include <iostream>

class Tree
{
public:
    void start()
    {
        std::function<void()> func([this]{this->doStart();});
        std::thread trd(func);
        trd.join();
    }
private:
    void doStart()
    {
        for (int i = 0; i < 5; ++i)
        {
            std::cout << i << std::endl;
        }
        return ;
    }
};

int main()
{
    Tree tree;
    tree.start();
}

标签:函数,对象,void,Tree,doStart,pthread,include
From: https://www.cnblogs.com/amazzzzzing/p/17540746.html

相关文章

  • system函数的风险和解决
    system函数的风险和解决源码摘录/*ExecuteLINEasashellcommand,returningitsstatus.*/staticintdo_system(constchar*line){intstatus=-1;intret;pid_tpid;structsigactionsa;#ifndef_LIBC_REENTRANTstructsigactionintr,quit;#e......
  • 粒子群算法PSO优化LSSVM最小二乘支持向量机惩罚参数c和核函数参数g,用于回归预测,有例子
    粒子群算法PSO优化LSSVM最小二乘支持向量机惩罚参数c和核函数参数g,用于回归预测,有例子,易上手,简单粗暴,直接替换数据即可。仅适应于windows系统。质量保证,完美运行。这段程序主要是一个基于粒子群优化算法(ParticleSwarmOptimization,PSO)的支持向量机(SupportVectorMachine,SVM)......
  • 西门子PID调节仿真程序,1200plc和1500plc通用,只需一个PLC实物,就能轻松实现PID工艺对象
    西门子PID调节仿真程序,1200plc和1500plc通用,只需一个PLC实物,就能轻松实现PID工艺对象的仿真,是学习PID的参数的好工具。针对这套程序,录制了一段视频解说,手把手教你如何使用博途PID调节工具和触摸屏PID画面的操作,非常值得拥有哦ID:7115632550149443......
  • 当函数遇上图片,比如Filter
    Filter函数可以说是包揽了一切查找,嗯,够辛苦。有木有想过,如果Filter遇上图片,又是怎样的风景呢?就是这个样几滴……这里的图片可以是两种,一种是由Image函数生成的,另一种是放置在单元格中的图片。其实,这并不是Filter的独享,因为图片作为单元格对象,所以几乎可以说是所有函数,都能对其进行......
  • js中的浏览器对象
    作为一种脚本语言,JavaScript代码不能独立运行,通常情况下我们需要借助浏览器来运行JavaScript代码,所有Web浏览器都支持JavaScript。除了可以在浏览器中执行外,也可以在服务端或者搭载了JavaScript引擎的设备中执行JavaScript代码,浏览器之所以能够运行JavaScript代码就......
  • Python | os.makedirs函数的使用
    概述os.makedirs()方法用于递归创建目录。如果子目录创建失败或者已经存在,会抛出一个OSError的异常,Windows上Error183即为目录已经存在的异常错误。如果第一个参数path只有一级,则mkdir()函数相同。语法makedirs()方法语法格式如下:os.makedirs(path,mode=0o777)参......
  • STL常用函数
    STL常用函数STL简介STL是StandardTemplateLibrary的简称,中文名称为标准模板库,从根本上讲,就是各种STL容器的集合,容器可以理解为能够实现很多功能的系统的函数。常见的容器有vector,stack,queue,map,set等。迭代器迭代器(iterators)是用来访问容器中的元素,类似于指针......
  • PostgreSQL-用户定义的函数
    PostgreSQL-用户定义的函数PostgreSQL是可扩展的,PostgreSQL服务器能够通过动态载入把用户编写的代码结合到自身中。也就是用户能够指定一个实现了新类型或函数的对象代码文件,并且PostgreSQL按要求载入它。主要讲的是查询语言函数与过程语言函数中的PL/pgSQL(SQL过程语言),其他......
  • 「高等数学」1.1.2 函数
    函数的概念定义:设数集\(D\subset\mathbf{R}\),则称映射\(f:D\rightarrow\mathbf{R}\)为定义在\(D\)上的函数,通常简记为\[y=f(x),x\inD,\]其中\(x\)称为自变量,\(y\)成为因变量,\(D\)称为定义域,记作\(D_f\),即\(D_f=D\).函数的定义中,对于每......
  • 面向对象三
    面向对象三一、static案例:publicclassPerson{//2:赋初始值{System.out.println("匿名代码块");}//1:只执行一次static{System.out.println("静态代码块");}//3publicPerson(){System.out.println("构造方法"......