简体   繁体   English

c++ 对由 function 返回的抽象 class 的调用方法

[英]c++ call method on abstract class returned by a function

I thing I'm missing something obvious but here is my problem我觉得我遗漏了一些明显的东西,但这是我的问题

with a pure abstract class IFoo带有纯抽象 class IFoo

class IFoo
{
 public:
    virtual bool isBar1() const=0;
    virtual bool isBar2() const=0;
};

and 2 implementations和 2 个实现

class Foo1 : public IFoo
{
 public:
    bool isBar1() const override { return true;}
    bool isBar2() const override { return false;}
};

class Foo2 : public IFoo
{
 public:
    bool isBar1() const override { return false;}
    bool isBar2() const override { return true;}
};

I have a managing class that must call the right method depending on a variable protocol我有一个管理 class 必须根据变量protocol调用正确的方法

class FooManager : public IFoo
{
 public:
    bool isBar1() const override 
    {
      switch(protocol)
      {
        case 1: return Foo1().isBar1();
        case 2: return Foo2().isBar1();
        default: return false;
      }
    }
    bool isBar2() const override
    {
      switch(protocol)
      {
        case 1: return Foo1().isBar2();
        case 2: return Foo2().isBar2();
        default: return false;
      }
    }
    void setProtocol(int proto){this->protocol = proto;}
 private:
    int protocol{0};
};

But there is a bunch of methods and I don't want to put the switch(protocol) everywhere given that it's really repetitive and new FooX could be added at anytime.但是有很多方法,我不想把switch(protocol)放在任何地方,因为它确实是重复的,并且可以随时添加新的 FooX。

How can I call the right override without using templates (given that protocol is dynamic and FooManager is persistent) and without using the heap on every call (through smart pointer or the likes because it's for an embedded project where we try to stay on the stack as much as possible).如何在不使用模板的情况下调用正确的覆盖(假设协议是动态的并且 FooManager 是持久的)并且在每次调用时不使用堆(通过智能指针等,因为它适用于我们试图留在堆栈上的嵌入式项目越多越好)。

I can't just create a getFoo() method that return IFoo because it's an abstract class And I can't return an IFoo& neither because it would return a reference to a temporary.我不能只创建一个返回 IFoo 的 getFoo() 方法,因为它是一个抽象的 class 而且我也不能返回 IFoo& 因为它会返回对临时的引用。

IFoo& FooManager::getFoo()
{
      switch(protocol)
      {
        case 1: return Foo1();
        case 2:
        default:  return Foo2();
      }
  //return reference to temporary
}

What else can I do?我还可以做些什么?

You could return a unique_ptr, such as可以返回一个 unique_ptr,例如

std::unique_ptr<IFoo> FooManager::getFoo() {
    switch (protocol) {
        case 1: return std::make_unique<Foo1>();
        case 2: 
        default: return std::make_unique<Foo2>();
    }
}

This would result in the data being a pointer and polymorphism being applied on calling the member functions这将导致数据成为指针,并且在调用成员函数时应用多态性

You can return a std::unique_ptr so you get polymorphic behavior but can control the lifetime of the returned object.您可以返回std::unique_ptr以便获得多态行为,但可以控制返回的 object 的生命周期。

std::unique_ptr<IFoo> FooManager::getFoo()
{
      switch(protocol)
      {
        case 1: return std::make_unique<Foo1>();
        case 2:
        default:  return std::make_unique<Foo2>();
      }
}

Since you have a very specific requirement I suggest a very specific solution for this exact problem (which may not be suitable elsewhere).由于您有一个非常具体的要求,我建议针对这个确切的问题提供一个非常具体的解决方案(这可能不适合其他地方)。 In order to avoid having to use dynamic allocation and pointers or references you can "fake" polymorphism using function pointers.为了避免必须使用动态分配和指针或引用,您可以使用 function 指针“伪造”多态性。 A small example given the requirements you mentioned in your comments:给出您在评论中提到的要求的一个小例子:

class Foo {
    public:
    // function pointer aliases to make them easier to use
    // I opted to make the two functions take different parameters for demonstration purposes
    using isBar1Func = bool(*)(const Foo*);
    using isBar2Func = bool(*)(int);
    // constructor requiring the function pointers as parameters
    Foo(int value, isBar1Func bar1func, isBar2Func bar2func) : 
        m_value(value), m_bar1Func(bar1func), m_bar2Func(bar2func) {}

    bool isBar1() const {
        return m_bar1Func(this);
    }

    bool isBar2() {
        return m_bar2Func(m_value);
    }

    int getValue() const {
        return m_value;
    }

    private:
       int m_value;
       isBar1Func m_bar1Func;
       isBar2Func m_bar2Func;
};

// example functions to be passed into the constructor
static bool testBar1Func(const Foo* foo) {
    return foo->getValue() != 0;
}

static bool testBar2Func(int value) {
    return value > 1;
}

// getFoo can simply return a copy
Foo FooManager::getFoo() {
    switch (protocol) {
        case 1: return Foo(1, testBar1Func, testBar2Func);
        // also works with non-capturing lambdas, which can be converted to function pointers
        case 2: return Foo(2, 
                           [](const Foo* foo) { return foo->getValue() != 1; },
                           [](int value) {return value != 12; });
        // add remaining cases as desired
    }
}

Thanks to @UnholySheep response, here is what I ended with:感谢@UnholySheep 的回复,这就是我的结尾:

class FooManager : public IFoo{
  public:
     using FooFunc = bool(*)(const IFoo&);

     bool callFoo(FooFunc function) const{
        switch(protocol) {
          case 1: return function(Foo1());
          case 2: return function(Foo2());
          //and the other cases
        }
    }
    bool isBar1() const override {
       return callFoo([](const IFoo& foo){return foo.isBar1();});
    }
    bool isBar2() const override {
       return callFoo([](const IFoo& foo){return foo.isBar2();});
    }
};

my FooX classes stay the sames and the switch(protocol) is in a single function meaning that if a new protocol arrives, I just have to create a new FooY for that protocol and add it to the switch to get it working.我的 FooX 类保持不变,并且switch(protocol)在单个 function 中,这意味着如果有新协议到达,我只需为该协议创建一个新的 FooY 并将其添加到 switch 以使其工作。 All that with compile time checks and no use of the heap.所有这些都带有编译时检查并且不使用堆。 Thanks again @UnholySheep and the others as well.再次感谢@UnholySheep 和其他人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM