C++ c++;对函数返回的抽象类调用方法

C++ c++;对函数返回的抽象类调用方法,c++,inheritance,abstract,C++,Inheritance,Abstract,我想我遗漏了一些明显的东西,但这是我的问题 使用纯抽象类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 overri

我想我遗漏了一些明显的东西,但这是我的问题

使用纯抽象类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 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};
};
但是有很多方法,我不想把
开关(协议)
放在任何地方,因为它确实是重复的,可以随时添加新的FooX

如何在不使用模板的情况下调用正确的覆盖(假设协议是动态的,而FooManager是持久的) 并且在每次调用时都不使用堆(通过智能指针或类似的方法,因为这是为了一个嵌入式项目,在这个项目中,我们尽量保持在堆栈上)

我不能仅仅创建一个返回IFoo的getFoo()方法,因为它是一个抽象类 而且我不能返回IFoo&因为它会返回对临时对象的引用

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

我还能做什么?

您可以返回一个
std::unique\u 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 FooManager::getFoo()
{
交换机(协议)
{
案例1:返回std::make_unique();
案例2:
默认值:返回std::make_unique();
}
}

您可以返回一个
std::unique\u 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 FooManager::getFoo()
{
交换机(协议)
{
案例1:返回std::make_unique();
案例2:
默认值:返回std::make_unique();
}
}
您可以返回一个唯一的\u ptr,例如

std::unique\ptr FooManager::getFoo(){
交换机(协议){
案例1:返回std::make_unique();
案例2:
默认值:返回std::make_unique();
}
}
这将导致数据成为指针,并在调用成员函数时应用多态性。您可以返回一个唯一的\u ptr,例如

std::unique\ptr FooManager::getFoo(){
交换机(协议){
案例1:返回std::make_unique();
案例2:
默认值:返回std::make_unique();
}
}

这将导致数据成为指针,并且在调用成员函数时应用多态性

,因为您有一个非常具体的要求,我建议针对这个确切的问题提供一个非常具体的解决方案(可能不适用于其他地方)。为了避免使用动态分配和指针或引用,可以使用函数指针“伪造”多态性。给出了您在评论中提到的要求的一个小示例:

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

由于您有一个非常具体的要求,我建议针对这个确切的问题提供一个非常具体的解决方案(可能不适用于其他地方)。为了避免使用动态分配和指针或引用,可以使用函数指针“伪造”多态性。给出了您在评论中提到的要求的一个小示例:

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)
在一个函数中,这意味着如果有新协议出现,我只需为该协议创建一个新的FooY,并将其添加到交换机中即可工作。所有这些都需要编译时检查,并且不使用堆。
再次感谢@UnholySheep和其他人。

感谢@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)
在一个函数中,这意味着如果有新协议出现,我只需为该协议创建一个新的FooY,并将其添加到交换机中即可工作。所有这些都需要编译时检查,并且不使用堆。
再次感谢@UnholySheep和其他人。

这些课程的目的是什么?在您的示例中,它们不包含任何状态或其他附加信息,因此您也可以使用函数指针这是一组帮助函数,它们只返回给定特定设备类型的bool。所有这些函数所需要的唯一信息是int。它是实类中的构造函数参数,但如果需要,也可以是函数参数。你能举一个使用函数指针的解决方案的例子吗?我想知道std::function或std::mem_fn甚至lambda是否是解决问题的好方法,但我现在无法访问我的工作站,因此无法直接尝试这些类的确切用途是什么?在您的示例中,它们不包含任何状态或其他附加信息,因此您也可以使用函数指针这是一组帮助函数,它们只返回给定特定设备类型的bool。所有这些函数所需要的唯一信息是int。它是实类中的构造函数参数,但如果需要,也可以是函数参数。你能举一个使用函数指针的解决方案的例子吗?我想知道std::function或std::mem_fn甚至lambda是否是解决这个问题的好方法,但我现在无法访问我的工作站,因此我无法直接尝试它,因为它仍然会在堆上创建对象。即使只是很短的时间。但是它很短,安全,可读性好,所以如果我找不到任何其他可以避免堆的东西,我会选择这个解决方案,因为它仍然会在堆上创建对象。即使只是很短的时间。但是它很短,安全,可读性好,所以如果我找不到任何其他可以避免它对我帮助很大的方法,我会选择这个解决方案。我真的需要提高我对函数指针的认识。我通常尽量避免使用它们,因为这会使代码更难阅读和理解,但我们在这里看到的情况并非总是如此。@BertrandThelen很高兴这有帮助。函数指针确实会让人困惑,但如果使用正确,在某些情况下它们会提供相当好的帮助。谢谢