我想在C++14上实现一些类似下面的东西,基本上派生类可以有不同类型的返回类型(例如int,double,string等)
class Base {
public:
virtual auto value() = 0; // I know this won't compile
};
class Derived1 : public Base {
public:
double value() override { return 1.0; };
};
class Derived2 : public Base {
public:
int value() override { return 1; };
};
我知道上面的代码不会编译,但我试图实现这样的东西,使用任何可能的方式或模式(我试过模板,CRTP,游客,但没有什么可以满足我下面的代码)
Derived1 d1;
Derived2 d2;
std::vector<Base*> base = { &d1, &d2 };
for (const auto* b : base)
std::cout << b->value();
我能用模板得到的最好的东西是这样的
Derived1 d1;
Derived2 d2;
std::vector<Base*> base = {&d1, &d2);
for (const auto* b : base)
if (dynamic_cast<Derived1>(b))
std::cout << b->value<double>();
else if (dynamic_cast<Derived2>(b))
std::cout << b->value<int>();
但是如果我有100种类型的Derived类,它看起来就不那么漂亮了
2条答案
按热度按时间x8diyxa71#
这在C中基本上是不可能的。C不以这种方式工作,原因很简单。让我们假设这种方式在某种程度上是可行的。考虑下面的简单函数:
现在问问你自己:
value
的类型是什么?2你可能不知道,但是在C中没有这样的类型auto
。3auto
是C编译器***的占位符,用于推导,或者在编译时确定实际的类型***。4auto
基本上是说:不管表达式的类型是什么,它就是这个对象的类型。如果你的C编译器确定p->value()
返回一个int
,那么value
就是一个int,上面的语句100%等价于声明int value=p->value();
。在这里,不可能确定
value
的实际类型。它是int
?还是double
?还是其他类型?不幸的是,这是一个永远无法解开的谜团,
type
的实际值取决于Base
指针实际指向的派生对象,这在编译时是***未知的***,只能在运行时*确定。C的一个基本属性是,***所有***对象的类型*必须在编译时推导出来。这是C固有的。没有变通方法。没有替代方法。您尝试做的事情在C中无法完成。
不过,也有一点好消息:如果可能的返回类型数量有限,只需声明一个普通的虚方法returns a
std::variant
,每个派生类就可以返回一个合适的值,调用者可以使用它。在上述情况下,这将是:
如果返回的实际值的类型是完全未知的,那么我想您可以使用
std::any
。在任何一种情况下,当您尝试实现任何一种方法时,您都会发现C++会***强制***您找出并检查每一种可能的类型(方式取决于您使用的是std::variant
还是std::any
),每次尝试使用此方法返回的值时。4xrmg8kj2#
抽象基类通常用作实现类的公共接口。在这种情况下,接口随每个子类而变化:当返回类型改变时,函数签名也改变,这就是为什么
override
会导致编译错误,正如你可能已经意识到的那样。Visitor非常有用,前提是类系统稳定,如here所述:
1.请确认当前层次结构(称为元素层次结构)相当稳定,并且这些类的公共接口足以满足访问者类所需的访问权限。如果不满足这些条件,则访问者模式不匹配。
要实现Visitor,通常需要定义多个具有不同输入参数类型的函数,而不是使用动态强制转换(如上面链接中所述)。
你也可以完全取消类继承。看看Sean Parent的talk。他描述了一个类似的用例,并使用模板来做你可能想做的事情。诀窍是定义一个类,它带有一个模板化的构造函数和一个on对象类型来与构造函数一起使用。