如何使用虚拟方法实现类

时间:2016-06-04 16:06:09

标签: c++ c++11 lambda

标题有点误导,但我不知道如何在一行中说出问题。

基本上,我使用的是具有此类定义的库:

class UCallbackWrapper {
   public:
      virtual UCallbackAction operator ()(const UMessage &)=0;
      virtual ~UCallbackWrapper() {}
};

我正在使用具有此声明的库的函数:

 UCallbackID setCallback(UCallbackWrapper & callback, const char * tag);

基本上,它接收UCallbackWrapper类型的对象作为参数(引用)。

如果在带有程序主函数的c ++文件中我使用正确的原型声明了一个函数,它允许我将它传递给setCallback函数,如下所示:

UCallbackAction onImageCallback(const UMessage &msg)
{
    // Some code here
}

int main(int argc, char *argv[])
{       
   setCallback(onImageCallback, "something"); // This works
}

现在,我想创建一个类,并在该类中使用setCallback函数,传递一个属于该类成员的函数。但是,如果我这样做,那么函数的原型来自

UCallbackAction onImageCallback(const UMessage &msg)

UCallbackAction (myClass::*)onImageCallback(const UMessage &msg)

我无法再将其传递给setCallback。

我尝试创建一个lambda函数,如下所示:

std::function<UCallbackAction(const UMessage &)> onImageCallback = [&] (const UMessage &msg) -> UCallbackAction {
    // Code here
};

setCallback(onImageCallback, "something");

但仍然不起作用,编译器说:

错误:没有匹配函数来调用'USyncClient :: setCallback(std :: function&amp;,const char [8])' 注意:参数1从'std :: function'到'UCallbackWrapper&amp;'没有已知的转换

所以,我考虑创建一个继承自UCallbackWrapper并实现虚方法的类(有点像我在Java中所做的那样),但我不知道如何在C ++中实现(或者可能)。

你能帮助我吗?或者也许指出一些我正在使用lambda函数做错的事情,或者反正的解决方法。

2 个答案:

答案 0 :(得分:2)

template<class F>
struct UCallbackWrapperImpl:UCallbackWrapper {
  F f;
  virtual UCallbackAction operator ()(const UMessage & m)final override{
    return f(m);
  }
};
using upUCallback=std::unique_ptr<UCallbackWrapper>;
template<class F>
upUCallback MakeUCallback(F&& f){
  return upUCallback(new UCallbackWrapperImpl<std::decay_t<F>>{std::forward<F>(f)});
}

将lambda传递给MakeUCallback并获得指向UCallbackWrapper的智能指针。

MakeUCallback重新调整指向api所期望的接口的智能指针。将此智能指针存储在回调的生命周期中。它将在最终超出范围时删除回调对象 - 您可以通过std::move将其扩展到另一个upUCallback

要使用api,请取消引用返回的upUCallback

请注意,api很奇怪,因为它将引用带到纯虚拟接口。我不知道这些api设计师在做什么,这不是一个好兆头。您可能需要调查api在UCallbackWrapper类中期望的生命周期管理:它们应该持续多长时间,谁删除它们等等。

在C ++中,您应该始终了解对象生存期要求。

答案 1 :(得分:2)

只需编写一个实现虚函数的类。您还可以将其自身注册为回调。

class MyCallback : public UCallbackWrapper {
public:
    UCallbackAction operator ()(const UMessage& message) override {
        // Some code here...
    }
    void registerAsCallback() {
        setCallback(*this, "something");  
    }
};

请注意,由于库API的设计,您有责任在库可能正在使用它时确保您的课程的生命周期:

int main() {
    MyCallback mcb;
    mcb.registerAsCallback();

    // Cause library to use callback here...
}

Live demo.