簡體   English   中英

c++ 對由 function 返回的抽象 class 的調用方法

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

我覺得我遺漏了一些明顯的東西,但這是我的問題

帶有純抽象 class IFoo

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

和 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;}
};

我有一個管理 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};
};

但是有很多方法,我不想把switch(protocol)放在任何地方,因為它確實是重復的,並且可以隨時添加新的 FooX。

如何在不使用模板的情況下調用正確的覆蓋(假設協議是動態的並且 FooManager 是持久的)並且在每次調用時不使用堆(通過智能指針等,因為它適用於我們試圖留在堆棧上的嵌入式項目越多越好)。

我不能只創建一個返回 IFoo 的 getFoo() 方法,因為它是一個抽象的 class 而且我也不能返回 IFoo& 因為它會返回對臨時的引用。

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

我還可以做些什么?

可以返回一個 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>();
    }
}

這將導致數據成為指針,並且在調用成員函數時應用多態性

您可以返回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>();
      }
}

由於您有一個非常具體的要求,我建議針對這個確切的問題提供一個非常具體的解決方案(這可能不適合其他地方)。 為了避免必須使用動態分配和指針或引用,您可以使用 function 指針“偽造”多態性。 給出您在評論中提到的要求的一個小例子:

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
    }
}

感謝@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();});
    }
};

我的 FooX 類保持不變,並且switch(protocol)在單個 function 中,這意味着如果有新協議到達,我只需為該協議創建一個新的 FooY 並將其添加到 switch 以使其工作。 所有這些都帶有編譯時檢查並且不使用堆。 再次感謝@UnholySheep 和其他人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM