什么是C++委托?

Sir*_*lot 137 c++ delegates delegation

C++中委托的一般概念是什么?它们是什么,它们如何使用以及它们用于什么?

我想首先以"黑匣子"的方式了解它们,但是关于这些事情的内容的一些信息也会很棒.

这不是最纯粹或最干净的C++,但我注意到我工作的代码库有很多.我希望能够理解它们,所以我可以使用它们,而不必深入研究可怕的嵌套模板.

这两个代码项目文章解释了我的意思,但不是特别简洁:

J.N*_*.N. 162

您有很多选择来实现C++中的委托.以下是我想到的.


选项1:仿函数:

可以通过实现来创建功能对象 operator()

struct Functor
{
     // Normal class/struct members

     int operator()(double d) // Arbitrary return types and parameter list
     {
          return (int) d + 1;
     }
};

// Use:
Functor f;
int i = f(3.14);
Run Code Online (Sandbox Code Playgroud)

选项2:lambda表达式(仅限C++ 11)

// Syntax is roughly: [capture](parameter list) -> return type {block}
// Some shortcuts exist
auto func = [](int i) -> double { return 2*i/1.15; };
double d = func(1);
Run Code Online (Sandbox Code Playgroud)

选项3:函数指针

int f(double d) { ... }
typedef int (*MyFuncT) (double d);
MyFuncT fp = &f;
int a = fp(3.14);
Run Code Online (Sandbox Code Playgroud)

选项4:指向成员函数的指针(最快的解决方案)

请参阅快速C++委托(在代码项目上).

struct DelegateList
{
     int f1(double d) { }
     int f2(double d) { }
};

typedef int (DelegateList::* DelegateType)(double d);

DelegateType d = &DelegateList::f1;
DelegateList list;
int a = (list.*d)(3.14);
Run Code Online (Sandbox Code Playgroud)

选项5:std :: function

(或者boost::function如果您的标准库不支持它).它比较慢,但它是最灵活的.

#include <functional>
std::function<int(double)> f = [can be set to about anything in this answer]
// Usually more useful as a parameter to another functions
Run Code Online (Sandbox Code Playgroud)

选项6:绑定(使用std :: bind)

允许提前设置一些参数,方便调用成员函数.

struct MyClass
{
    int DoStuff(double d); // actually a DoStuff(MyClass* this, double d)
};

std::function<int(double d)> f = std::bind(&MyClass::DoStuff, this, std::placeholders::_1);
// auto f = std::bind(...); in C++11
Run Code Online (Sandbox Code Playgroud)

选项7:模板

只要它与参数列表匹配就接受任何内容.

template <class FunctionT>
int DoSomething(FunctionT func)
{
    return func(3.14);
}
Run Code Online (Sandbox Code Playgroud)

  • 它们本身不存在于 C++ 中。因此列表。 (3认同)
  • 好的名单,+ 1.但是,在这里只有两个真正算作代理 - 捕获lambdas和从`std :: bind`返回的对象,并且两者都做同样的事情,除了lambda不是多态的,因为它们可以接受不同的参数类型. (2认同)
  • @SirYakalot某个行为类似于函数的东西,但它可以同时保持状态,并且可以像任何其他变量一样进行操作.例如,一个用途是采用一个带有两个参数的函数,并强制第一个参数具有某个值,用一个参数创建一个新函数(我的列表中的`binding`).你无法用函数指针实现这一点. (2认同)

Gri*_*ner 34

委托是一个包装对象实例的指针或引用的类,该对象实例上要调用的该对象的类的成员方法,并提供触发该调用的方法.

这是一个例子:

template <class T>
class CCallback
{
public:
    typedef void (T::*fn)( int anArg );

    CCallback(T& trg, fn op)
        : m_rTarget(trg)
        , m_Operation(op)
    {
    }

    void Execute( int in )
    {
        (m_rTarget.*m_Operation)( in );
    }

private:

    CCallback();
    CCallback( const CCallback& );

    T& m_rTarget;
    fn m_Operation;

};

class A
{
public:
    virtual void Fn( int i )
    {
    }
};


int main( int /*argc*/, char * /*argv*/ )
{
    A a;
    CCallback<A> cbk( a, &A::Fn );
    cbk.Execute( 3 );
}
Run Code Online (Sandbox Code Playgroud)

  • 而不是Execute,我强烈建议在你的情况下覆盖调用操作符 - void CCallback :: operator()(int).其原因在于通用编程,可调用对象有望像函数一样被调用.o.Execute(5)将是不兼容的,但是o(5)很适合作为可调用的模板参数.这个类也可以推广,但我认为你保持简洁(简洁)(这是一件好事).除了那个挑剔之外,这是一个非常有用的课程. (3认同)

Bit*_*ler 15

对C++委托实施的需求是对C++社区的持久尴尬.每个C++程序员都喜欢拥有它们,所以尽管事实如下:

  1. std::function() 使用堆操作(并且对于严肃的嵌入式编程来说是遥不可及的).

  2. 所有其他实现都对可移植性或标准符合性做出更大或更小程度的让步(请通过检查此处和代码项目中的各种委托实现来验证).我还没有看到不使用野生reinterpret_casts,嵌套类"原型",这有望产生同样大小的一个用户传递的函数指针,编译器的技巧,比如第一向前声明的实现,那么的typedef然后再次申报,这次继承自另一个类或类似的阴暗技术.虽然对于构建它的实现者来说这是一个很大的成就,但对于C++如何发展仍然是一个悲伤的证据.

  3. 它很少被指出,现在超过3个C++标准版本,代表没有得到妥善解决.(或者缺乏允许直接委托实现的语言功能.)

  4. 通过标准定义C++ 11 lambda函数的方式(每个lambda具有匿名,不同类型),在某些用例中情况才得到改善.但是对于在(DLL)库API中使用委托的用例,单独使用lambdas 仍然无法使用.这里常见的技术是首先将lambda打包成std :: function,然后将其传递给API.

  • 这个答案更像是咆哮而不是实际答案 (7认同)
  • 我在嵌入式系统中使用std :: function而没有堆,它仍然可以工作。 (2认同)
  • `std::function` 并不总是动态分配 (2认同)

Sir*_*lot 6

很简单,委托提供函数指针应该如何工作的功能.C++中的函数指针存在许多局限性.委托使用一些幕后模板讨厌来创建模板类函数 - 指针类型的东西,它以你可能想要的方式工作.

即 - 您可以将它们设置为指向给定的功能,您可以随时随地传递它们并随时随地调用它们.

这里有一些很好的例子:


Joe*_*Joe 5

此处未提及的 C++ 中委托的一个选项是使用函数 ptr 和上下文参数来实现 C 风格。这可能与许多提出此问题的人试图避免的模式相同。但是,该模式是可移植的、高效的,并且可用于嵌入式和内核代码。

class SomeClass
{
    in someMember;
    int SomeFunc( int);

    static void EventFunc( void* this__, int a, int b, int c)
    {
        SomeClass* this_ = static_cast< SomeClass*>( this__);

        this_->SomeFunc( a );
        this_->someMember = b + c;
    }
};

void ScheduleEvent( void (*delegateFunc)( void*, int, int, int), void* delegateContext);

    ...
    SomeClass* someObject = new SomeObject();
    ...
    ScheduleEvent( SomeClass::EventFunc, someObject);
    ...
Run Code Online (Sandbox Code Playgroud)