我已经看过一些关于这个问题的帖子,但没有总结我目前情况下所有选项的内容,可能还有我没有考虑的解决方案。
我的情况非常普遍我有几个类Inf1
Inf2
(更像是接口)都有纯虚方法。
Inf1
有方法
(Inf2& or Inf2* or shared_pointer) foo(/** Some info on how to build the object**/) = 0
(这是问题的一部分)。
在Inf1
的实现中,在实现Inf2
时返回foo
的各种实现。
Inf2
实现相对较小,所以我不介意按值返回它们,因此将它们复制到结果中,但我不能声明foo
只返回Inf2
因为然后我将返回一个抽象对象。
任何优选的或创造性的方法来解决这个问题? :)
答案 0 :(得分:3)
所以你有类型Inf1
和Inf2
,它们彼此相关,并且其中至少有一个包含抽象方法。
您想要返回Inf2
的一些子实现,但是哪一个是在运行时决定的。
这意味着您需要运行时多态性。有三种不同的方法可以解决这个问题。
首先,您可以向公共接口返回一个指针 - 可能是一个智能指针,如unique_ptr
。这需要免费存储(堆)分配,但是使所有权变得清晰,并且是最简单的答案。
其次,您可以编写一个类型擦除对象,该对象公开virtual
接口的非Inf2
版本,并转发到某些内部细节。这些内部细节最终将使用某种智能指针或第三种解决方案。这里的优点是你可以隐藏你如何管理内存,并简单地通过廉价的移动来暴露价值语义。缺点是有很多样板。
第三,你可以在一组类型上使用boost::variant
- union
之类的东西来防止访问错误的类型。虽然可能无法直接使用boost
,但可以模仿设计。我们的想法是,您有一些本地存储,您可以在其中放置新数据,但对于较大的对象,您可以使用智能指针。与第二种解决方案不同,您支持的类型集明确列在您的类型中。这是最难的解决方案(如果您至少无法访问boost
),并且要求Inf2
的一组固定(在编译时)实现Inf1
的所有用户{{1}} 1}}必须有完整的详细信息。
如上所述,第一个解决方案是最简单的。第一个解决方案的成本仅仅是基于性能的,如果您发现它们存在真正的问题,那么这些性能命中并不难解决。因此,我会建议解决方案#1,然后进行分析,看看所涉及的成本是否过高。如果成本很高,请转到解决方案#3,可能在解决方案#2包装器中。
答案 1 :(得分:2)
您的问题实际上是关于内存管理。 Inf2
的多态子类可以是任意大的,并且在编译时不知道最大的子类,因此您不能以自动存储持续时间存储它们,因此它们不能按值返回 - 因此您需要管理至少在回报中以某种方式为他们记忆
Inf2
子类类型的对象应该存储在哪里?何时以及何时删除Inf2
的实施。对此的答案通常决定了使用什么样的句柄概念。例如,如果在内存池中分配Inf2实现,则返回Inf2*
就可以了。如果您想要单一所有权,也可以使用unique_ptr<Inf2>
,但是您无法复制句柄。如果要复制句柄,也可以使用shared_ptr<Inf2>
,但是必须小心循环,效率稍差。您还可以创建一个包装类Inf2Handle
,它可以执行更复杂的操作,例如写时复制或其他操作。
您提到实现很小,因此内存池可能是最好的架构。
哪个是最佳选择,实际上取决于Inf1
和Inf2
的使用方式。