简体   繁体   English

c ++动态返回类型

[英]c++ dynamic return type

I'm not sure if this is a thing (to be honest I want to say that it is not), but I was wondering if there is a way to write a c++ function so that it can choose which type of object to return. 我不确定这是否是一个东西(说实话我想说它不是),但我想知道是否有办法编写一个c ++函数,以便它可以选择返回哪种类型的对象。

For example, I have a base class ( A ) that has 3 child classes ( Aa , Ab , Ac ). 例如,我有一个基类( A ),它有3个子类( AaAbAc )。 In a factory( F ) class I have a std::map<UINT, A*> that holds a number of the child classes based on a UINT id . 在工厂( F )类中,我有一个std::map<UINT, A*> ,它根据UINT id保存了许多子类。 My goal is to write a function that can build and return the correct object when I pass in an id value. 我的目标是编写一个函数,当我传入一个id值时,它可以构建并返回正确的对象。

I'll probably end up returning pointers and cloning the data that they point to, but I was just curious as to whether or not the aforementioned was actually possible. 我可能最终会返回指针并克隆他们指向的数据,但我只是好奇上述内容是否真的可行。

Thanks! 谢谢!

C++ being statically typed, the return type of a function must be known at compile time. C ++是静态类型的,函数的返回类型必须在编译时知道。 From here arises the question: 从这里出现了一个问题:

  1. do I know the expected return type statically on each call site of F (== it only depends on constant expression values) F每个调用站点上静态地知道预期的返回类型(==它仅取决于constant expression值)
  2. or does it depend on some runtime variable. 或者它取决于某些运行时变量。

For case #1, a function template for F would be a good approach. 对于情况#1, F的函数模板将是一种很好的方法。
But in your case, it seems you are facing #2 (because you want to return a type depending on ID that we can assume is not a constant expression). 但在你的情况下,你似乎面临#2(因为你想要返回一个类型,取决于我们可以假设不是常量表达式的ID )。

Because of the static typing, if you are to write a function (assuming you do not overload it, because it seems your input parameters are always the same), it will have a single and well-defined return type. 因为静态类型的,如果你是编写一个函数(假设你不超载,因为它似乎你的输入参数都是一样的),这将有一个单一的和明确的返回类型。 Basically, you do not have a syntax to say that your factory F will return either an Aa Ab or Ac (and that is a very good thing, with regard to static typing and all the compiler verifications it enables ; ) 基本上,你没有语法说你的工厂F将返回Aa AbAc (这是一个非常好的事情,关于静态类型和它启用的所有编译器验证;)

C++ solution: Type erasure C ++解决方案:键入擦除

With that being said, you have a few approaches to type erasure , that will allow you to return an instance of a variant type hidden behind a common single type. 话虽如此,您可以使用一些方法来键入擦除 ,这将允许您返回隐藏在常见单一类型后面的变体类型的实例。

  • The obvious one is the pointer-to-derived to pointer-to-base conversion. 显而易见的是指针到指针到基础的转换。 It is particularly usefull if you plan to use the returned object mainly through its A interface (ie, you will call the virtual functions defined on A ). 如果您计划主要通过其A接口使用返回的对象(即,您将调用在A定义的虚函数),这将特别有用。

     A* F(ID aId) 

    This A* could point to any type deriving from A . 这个A*可以指向任何来自A类型。 From here, you could call every function defined on A public interface on the returned pointer. 从这里,您可以在返回的指针上调用A公共接口上定义的每个函数。 Of course, if you wanted to call an operation that is only available on a subclass, you would need to know what is the exact type on call site,and then cast the pointer to a pointer-to-derived before being able to call the operation. 当然,如果你想调用一个只在子类上可用的操作,你需要知道调用站点上的确切类型是什么,然后将指针强制转换为指向派生的指针,然后才能调用操作。

  • A possible alternative, if you'd rather avoid dynamic memory, could be boost::variant . 如果您宁愿避免动态内存,可能的替代方案可能是boost::variant At the cost of having to explicitly list all the possible types the function could return. 以必须明确列出函数可能返回的所有可能类型为代价。

     boost::variant<Aa, Ab, Ac> F(ID aId); 

    You can take a look at the tutorial for a quick introduction to the syntax and features. 您可以查看本教程 ,快速了解语法和功能。

Sure, something like this: 当然,这样的事情:

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

However, since you are storing the pointers to base types, you can as well return them as is, and rely on the caller to make a specific cast, if that goes well with your application's architecture. 但是,由于您将指针存储到基类型,因此您也可以按原样返回它们,并依赖调用者进行特定的转换,如果这与您的应用程序的体系结构相符合。

Unfortunately, you can not do it fully automatically. 不幸的是,你无法完全自动完成。 Sooner or later you will have to determine the exact class that hides behind the base class pointer, and make a cast. 迟早你必须确定隐藏在基类指针后面的确切类,并进行强制转换。 With the template solution it is done "sooner": 使用模板解决方案,它可以“更快”完成:

MyDerivedType * value = myMapClassInstance.getValue<MyDerivedType>(1);

If you prefer to return the base pointer, it is done "later": 如果您希望返回基指针,则会“稍后”完成:

BaseType * value = myMapClassInstance.at(1);
MyDerivedType * exactValue = dynamic_cast<MyDerivedType*>(value);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM