[英]C++ how to call a method defined in a class directly where only the reference to the class is returned by another function
[英]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.