c++;动态返回类型 我不确定这是不是一件事(老实说,我想说不是),但我想知道是否有一种方法来写C++函数,以便它可以选择返回哪种类型的对象。
例如,我有一个基类(c++;动态返回类型 我不确定这是不是一件事(老实说,我想说不是),但我想知道是否有一种方法来写C++函数,以便它可以选择返回哪种类型的对象。,c++,polymorphism,C++,Polymorphism,例如,我有一个基类(a),它有3个子类(Aa,Ab,Ac)。在工厂(F)类中,我有一个std::map,它根据UINT id保存了许多子类。我的目标是编写一个函数,当我传入一个id值时,它可以构建并返回正确的对象 我可能最终会返回指针并克隆它们所指向的数据,但我只是好奇上述操作是否真的可行 谢谢 当然,是这样的: class MyMapClass { public: template< class ExactType > ExactType * getValue(UINT k
a
),它有3个子类(Aa
,Ab
,Ac
)。在工厂(F
)类中,我有一个std::map
,它根据UINT id
保存了许多子类。我的目标是编写一个函数,当我传入一个id值时,它可以构建并返回正确的对象
我可能最终会返回指针并克隆它们所指向的数据,但我只是好奇上述操作是否真的可行
谢谢 当然,是这样的:
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;
}
类MyMapClass
{
公众:
模板ExactType*getValue(UINT键)
{
返回动态_cast(_myMap.at(key));
}
基本类型*at(UINT键)
{
返回_myMap.at(键);
}
私人:
std::map\u myMap;
}
但是,由于您存储的是指向基类型的指针,因此您也可以按原样返回它们,并依赖调用者进行特定转换(如果这与应用程序的体系结构相符合的话)
不幸的是,您不能完全自动完成此操作。迟早要确定隐藏在基类指针后面的确切类,并进行转换。使用模板解决方案,“更快”完成:
MyDerivedType*value=myMapClassInstance.getValue(1);
如果希望返回基指针,则在“以后”完成:
BaseType*value=myMapClassInstance.at(1);
MyDerivedType*exactValue=动态转换(值);
C++是静态类型的,必须在编译时知道函数的返回类型。由此产生了一个问题:
F
的每个调用站点上的预期返回类型(==它仅取决于常量表达式
值)F
的函数模板将是一个很好的方法。但在您的例子中,您似乎面临着#2(因为您希望返回一个依赖于
ID
的类型,我们可以假定它不是一个常量表达式)
由于静态类型,如果您要编写一个函数(假设您没有重载它,因为您的输入参数似乎总是相同的),它将有一个单一的和定义良好的返回类型。基本上,您没有语法来说明您的工厂F
将返回Aa
Ab
或Ac
(对于静态类型和它启用的所有编译器验证来说,这是一件非常好的事情;)
C++解决方案:类型删除
话虽如此,您有几种类型擦除的方法,这将允许您返回隐藏在普通单一类型后面的变体类型的实例
- 最明显的一个是从指针到派生到指针到基的转换。如果您计划主要通过其
接口使用返回的对象(即,您将调用A
上定义的虚拟函数),那么它尤其有用 这个A
可以指向从A*
派生的任何类型。从这里,您可以在返回的指针上调用A
公共接口上定义的每个函数。当然,如果您想调用一个只在子类上可用的操作,那么您需要知道调用站点上的确切类型,然后将指针强制转换为派生的指针,然后才能调用该操作
- 如果您希望避免使用动态内存,一种可能的替代方法是
。代价是必须显式列出函数可能返回的所有可能类型boost::variant
boost::variant<Aa, Ab, Ac> F(ID aId);
boost::variant,快速介绍语法和功能
Ab get(标准:积分常数)代码>真棒的答案,谢谢你的洞察力!我可能会使用指针选项,但是这个boost::variant概念非常有趣,我必须稍微考虑一下。
BaseType * value = myMapClassInstance.at(1);
MyDerivedType * exactValue = dynamic_cast<MyDerivedType*>(value);
A* F(ID aId)
boost::variant<Aa, Ab, Ac> F(ID aId);