将继承类对象的向量传递给期望基类向量的函数

3

我正在使用一个继承自OpenCV Rect的A类。A类只是在执行期间添加了一些我想要跟踪的变量。

class A: public Rect { //code, constructors... }

我希望使用opencv方法detectMultiScale,它需要一个空的vector<Rect>并将其填充为期望的输出结果。
我应该如何传递一个继承自Rect的空向量,即vector<A>,并期望在方法中捕获基类?(我此时明白这个方法是黑箱,我不想编译opencv来重新声明一些内容。)

5
一个 vector<Rect> 和一个 vector<A> 是两种完全不同的类型。如果函数需要一个 vector<Rect>,你必须发送一个 vector<Rect>,不能发送其他类型。 - PaulMcKenzie
3
另外,为什么要从“矩形(Rect)”派生,当它并不适合被派生使用。如果“矩形(Rect)”有虚析构函数那是另一回事,但“矩形(Rect)”的设计者从未打算让其用于你正在使用的目的。也许将“矩形(Rect)”作为“A”的成员而不是从“矩形(Rect)”派生“A”可能更好。 - PaulMcKenzie
3
谷歌搜索"一个苹果袋子不是一个水果袋子"。 - n. m.
如果性能不会受到影响,你可以在需要时将所有的矩形合并成一个向量,然后使用该向量调用函数。或者你可以采取更危险的方式,创建一个 vector<Rect>,并让每个 A 拥有指向 vector<Rect> 中某个项目的指针 -- 需要注意的是,必须确保向量永远不会被调整大小,因为指向向量中元素的指针在调整大小时可能会失效。 - PaulMcKenzie
@AlejandroSazo,这里的性能方面有哪些关键因素?如果复制Rect很耗费资源,可以在A中存储std::vector的索引。并将向量本身存储在某个地方。 - StoryTeller - Unslander Monica
显示剩余5条评论
2个回答

1
我担心那样做行不通,你需要使用 std::vector<Rect*> - 直觉上讲,这是因为 sizeof(Rect) != sizeof(A),所以即使是索引也会失败,更不用说对于 std::vector<Rect> 的类布局。可以使用指针,或者如果你有一组固定的类型,可以尝试 variant 和 visitors。
编辑:如果你的使用情况 (detectMultiScale) 不允许你传递 vector<std::Rect*>,那么你可以从各种修饰符-visitor 实现中选择。在这种情况下,你必须放弃直接继承。以下是一些例子:
  • 有一个 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) 这并不一定是正确的。如果一个类没有添加成员,它的大小与其基类相同。然而,在一般情况下不应该假设这一点是正确的。 - StoryTeller - Unslander Monica
1
此外,在cv::CascadeClassifier::detectMultiScale的上下文中(参见OP),使用vector<Rect*>根本行不通。 - StoryTeller - Unslander Monica
@StoryTeller:已编辑以修复该问题。此外,在我所使用的几乎所有架构中,如果没有其他非静态字段(包括虚拟字段 - 新的或重载的)和其他非空基类(并且sizeof标准保持不变),这种方法会有所作用 - 但仍然是未定义行为,所以不要告诉任何人 :) 这是由于内存组织方式的原因。 - lorro
@StoryTeller:根据第二条评论进行了编辑,谢谢。 - lorro
@StoryTeller 或者更准确地说,不添加任何成员变量,只重用现有的基类虚表。 - Justin Time - Reinstate Monica

1
无法实现。该函数需要一个Rect对象的向量,因此您必须传递这个对象。
如果您想要一个A的向量,那么您可以编写一个构造函数A(Rect),它接受基类的实例作为参数,并相应地初始化子对象。然后编写一个循环来转换获取的Rect实例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接