amazzzzzing

导航

函数对象

函数对象

定义

定义了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();
}

posted on 2023-07-10 12:14  amazzzzzing  阅读(55)  评论(0)    收藏  举报