我不确定这是否是一件事(说实话我想说它不是),但我想知道是否有办法编写c ++函数以便它可以选择哪种类型要返回的对象。
例如,我有一个基类(A
),它有3个子类(Aa
,Ab
,Ac
)。在工厂(F
)类中,我有一个std::map<UINT, A*>
,它基于UINT id
包含许多子类。我的目标是编写一个函数,当我传入一个id值时,它可以构建并返回正确的对象。
我可能最终会返回指针并克隆他们指向的数据,但我只是好奇上述内容是否真的可行。
谢谢!
答案 0 :(得分:2)
C ++是静态类型的,函数的返回类型必须在编译时才知道。从这里出现了一个问题:
F
的每个呼叫网站上静态了解预期的返回类型(==它仅取决于constant expression
值)对于案例#1,F
的函数模板将是一个很好的方法
但在你的情况下,你似乎面临#2(因为你想要返回一个取决于ID
的类型,我们可以假设它不是一个常量表达式。)
由于静态类型,如果你要写一个函数(假设你没有超载它,因为看起来你的输入参数总是相同的),它将有一个单个和井 - 定义的返回类型。基本上,您没有语法表明您的工厂F
将返回Aa
Ab
或Ac
(这是一件非常好的事情,关于静态类型和它启用的所有编译器验证;)
话虽如此,你有一些类型擦除的方法,这将允许你返回隐藏在常见单一类型后面的变体类型的实例。
显而易见的是指针到指针到基础的转换。如果您计划主要通过其A
接口使用返回的对象(即,您将调用A
上定义的虚函数),这将特别有用。
A* F(ID aId)
此A*
可以指向源自A
的任何类型。从这里,您可以在返回的指针上调用A
公共接口上定义的每个函数。当然,如果你想调用一个只在子类上可用的操作,你需要知道调用站点上的确切类型是什么,然后将指针强制转换为指向派生的指针,然后才能调用操作
如果您宁愿避免使用动态内存,可能的替代方法可能是boost::variant
。以必须明确列出函数可能返回的所有可能类型为代价。
boost::variant<Aa, Ab, Ac> F(ID aId);
您可以查看the tutorial,快速了解语法和功能。
答案 1 :(得分:1)
当然,这样的事情:
class MyMapClass
{
public:
template< class ExactType > ExactType * getValue(UINT key)
{
return dynamic_cast<ExactType*>(_myMap.at(key));
}
BaseType * at(UINT key)
{
return _myMap.at(key);
}
private:
std::map<UINT, BaseType*> _myMap;
}
但是,由于您将指针存储到基类型,因此您也可以按原样返回它们,并依赖调用者进行特定的转换,如果这与您的应用程序的架构相符合的话。
不幸的是,你无法完全自动完成。迟早你必须确定隐藏在基类指针后面的确切类,并进行强制转换。使用模板解决方案,可以更快地完成#34;
MyDerivedType * value = myMapClassInstance.getValue<MyDerivedType>(1);
如果您希望返回基本指针,则会在&#34;稍后&#34;
完成BaseType * value = myMapClassInstance.at(1);
MyDerivedType * exactValue = dynamic_cast<MyDerivedType*>(value);