天天看点

c++ 如何优雅的传递函数以及类成员函数std::function

在一般的方法中,基本上传递函数都是通过传递函数指针的方式来实现。但是最近发现,频繁的传递函数、类成员函数不太是一个好的办法,所以在这里梳理一下常见的几种方法以及如何更方便的传递函数。

如果是普通函数的话,一般这样

#include <iostream>
int add(int a, int b)
{
	return a + b;
}
int main()
{
	int (*func) (int, int);
	func = add;
	std::cout << "func :\t" << func(10, 20) << std::endl;
    std::cout << "Hello World!\n";
	getchar();
}
           
c++ 如何优雅的传递函数以及类成员函数std::function

如果是类成员函数的话,我这里使用两个类A和B,在B类中存放A类的函数,然后通过B类的方法来调用A类指定的那个成员函数,

A.h

#pragma once

#include <iostream>

class A

{

public:

    int add(int a,int b) {

        std::cout << "Hello A:func" << std::endl;

        return a + b;

    }

};

 B.h

#pragma once

#include <iostream>

class A;        //前向声明

class B

{

public:

    A *locala;

    int (A::*func)(int ,int);

    int run() {

        return (locala->*func)(10, 20);

    }

};

main.cpp

#include <iostream>
#include "A.h"
#include "B.h"
int main()
{
	A a;
	B b;
	b.locala = &a;
	b.func = &A::add;
	std::cout << "Class B func return :\t"<<b.run() << std::endl;;
    std::cout << "Hello World!\n";
	getchar();
}
           

输出结果:

c++ 如何优雅的传递函数以及类成员函数std::function

在实际使用中,如果传入的类不同,以及函数的参数发生改变等情况,都会产生十分麻烦的修改程序代码的问题,而且频繁使用这种方式来实现代码也违背了程序的许多设计原则,在这里我们可以看一下C++11 的新标准

std::function

std::function

C++

Utilities library

Function objects

std::function

Defined in header 

<functional>

template< class >

class function; 

(since C++11)

template< class R, class... Args >

class function<R(Args...)>;

(since C++11)
Class template 

std::function

 is a general-purpose polymorphic function wrapper. Instances of 

std::function

 can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.

The stored callable object is called the target of 

std::function

. If a 

std::function

 contains no target, it is called empty. Invoking the target of an empty 

std::function

 results in std::bad_function_call exception being thrown.

std::function

 satisfies the requirements of CopyConstructible and CopyAssignable.

机翻:

类模板std :: function是通用的多态函数包装器。 std :: function的实例可以存储,复制和调用任何CopyConstructibleCallable目标-函数,lambda表达式,bind表达式或其他函数对象,以及指向成员函数的指针和指向数据成员的指针。

存储的可调用对象称为std :: function的目标。 如果std :: function不包含目标,则称为空。 调用空std :: function的目标会导致std :: bad_function_call抛出异常。

std :: function满足CopyConstructible和CopyAssignable的要求。

简单来说,function是一个封装,它可以针对可复制的、可调用的对象或者函数,当调用一个function对象时,如果这个对象是空的,就会抛出std :: bad_function_call这个异常,我们可以捕捉这个异常。最后,function是可复制可拷贝赋值的。

通过function和bind函数,在这里将类成员函数的调用重新实现一下:

A.h

#pragma once

#include <iostream>

class A

{

public:

    int add(int a,int b) {

        std::cout << "Hello A:func" << std::endl;

        return a + b;

    }

};

B.h

#pragma once

#include <iostream>

#include <functional>

class A;        //前向声明

class B

{

public:

    std::function<int(int one, int two)> localfunc;

    int run() {

        return localfunc(10, 20);

    }

};

main.cpp

#include <iostream>
#include "A.h"
#include "B.h"
int main()
{
	A a;
	B b;
	b.localfunc = std::bind(&A::add, &a, std::placeholders::_1, std::placeholders::_2);
	std::cout << "Class B func return :\t"<<b.run() << std::endl;;
    std::cout << "Hello World!\n";
	getchar();
}

           

 输出结果:

c++ 如何优雅的传递函数以及类成员函数std::function

这样实现的好处就是,在B类中先定义了localfunc这个函数,它指定了两个参数,后期调整的话,如果扩展参数或者减少参数,我们可以直接更改bind函数对应的参数列表。

因此,它可以被用于回调机制,暂时保管函数或函数对象,在之后需要的时候再使用,使回调机制拥有更多的弹性。(我主要就是用它来实现回调函数)

继续阅读