将继承的类对象的向量传递给期望基类向量的函数
Posted
技术标签:
【中文标题】将继承的类对象的向量传递给期望基类向量的函数【英文标题】:Pass vector of inherited class object to function expecting base class vector 【发布时间】:2016-07-18 16:31:36 【问题描述】:我正在使用继承自 opencv Rect 的 A 类。 A 只是添加了一些我想在执行期间跟踪的变量。
class A: public Rect //code, constructors...
我想使用 opencv 方法 detectMultiScale
,它需要一个空的 vector<Rect>
,然后用预期的输出填充它。
如何传递一个空的继承对象向量,即来自 Rect 的 vector<A>
并期望在方法中捕获基类? (此时我明白了,方法是一个黑盒子,我不想编译opencv重新声明一些东西)。
【问题讨论】:
vector<Rect>
和vector<A>
是两种完全不同的类型。如果函数需要vector<Rect>
,则需要发送vector<Rect>
,仅此而已。
另外,你为什么要从 Rect
派生而不是派生自它。如果Rect
有一个虚拟析构函数,那是一回事,但Rect
的设计者从来没有打算将它用于您使用它的目的。也许Rect
应该是A
的成员,而不是从Rect
派生A
。
就像保罗说的那样,您似乎在滥用公共继承。 A
更有可能必须拥有 Rect
或通过其他方式与其中一个关联。
我之前的方案是一个拥有一个矩形的类,我想我可以扩展。回到旧的(但正确的)设计。
谷歌“一袋苹果不是一袋水果”。
【参考方案1】:
如何传递一个空的继承对象向量,即来自 Rect 的向量并期望在方法中捕获基类?
这是不可能的。该函数需要一个Rect
对象的向量,所以这是您必须传递的。
如果你想要一个A
的向量,那么你可以编写一个构造函数A(Rect)
,它接受一个基类的实例作为参数,并相应地初始化基子对象。然后编写一个循环来转换获取的Rect
实例。
【讨论】:
【参考方案2】:恐怕这行不通,您将不得不使用std::vector<Rect*>
- 直观地说,这是在sizeof(Rect) != sizeof(A)
时出现的,所以即使您的索引也会失败,更不用说类布局了,对于std::vector<Rect>
。指针,或者,如果你有一组固定的类型,你可以试验变体和访问者。
编辑:如果您的用例 (detectMultiScale
) 不允许您传递 vector<std::Rect*>
,您可以从各种装饰器访问器实现中进行选择。在这种情况下,您必须放弃直接继承。举个例子:
有一个std::vector<Rect>
和一个std::vector<ARectV>
。 ARectV
包含在 Rect
中找不到的其他字段。
Rect
。在这种情况下,构造函数将填充 Rect;或
您的 ARectV
方法可能采用(可能是 const)Rect&
,在这种情况下,您的构造函数不需要存储它
如果所有其他方法都失败,请使用静态 std::map<Rect*, ARectV> sARectV
。这会更慢并且需要手动插入/删除(可能在 sARectV 的构造函数/析构函数中,前者采用 - 可能是 const - Rect*
或 Rect&
),但允许您编写:sARectV[&rect].yourfunction()
。当然,它也允许使用标准符号,即Rect rect; ARectV rectv(rect); rectv.yourfunction();
- 但您可能无法将rv
传递给应该采用Rect*
或Rect&
的回调。如果他们按价值计算Rect
,那你就倒霉了。
【讨论】:
sizeof(Rect) != sizeof(A)
实际上可能并非如此。如果一个类不添加任何成员,则其大小与其基类相同。然而,在一般情况下不假设它是正确的。
另外,在cv::CascadeClassifier::detectMultiScale
的上下文中(参见OP),使用vector<Rect*>
根本行不通。
@StoryTeller:已编辑以解决该问题。此外,在我曾经使用过的几乎所有架构上,如果没有额外的非静态字段(包括虚拟 - 新的或重载的)并且没有其他非空基类(并且 sizeof
标准成立),这将排序工作 - 但仍然是 UB,所以不要告诉任何人 :) 这是由于内存的组织方式。
@StoryTeller:根据第二条评论编辑,谢谢。
@StoryTeller 或者更准确地说,不添加成员变量,只重用已有的基类 vtables。以上是关于将继承的类对象的向量传递给期望基类向量的函数的主要内容,如果未能解决你的问题,请参考以下文章