简体   繁体   English

将具有继承同一类的不同类型的对象存储在容器中

[英]Store objects with different types that inherit the same class in a container

I have the following classes: 我有以下课程:

class ActivityItem : public QGraphicsItem;
class DeadTimeItem : public QGraphicsItem;

I am at a point where I need to store both objects of type ActivityItem and DeadTimeItem in the same container so I can work with them together. 我现在需要将ActivityItemDeadTimeItem类型的两个对象存储在同一容器中,以便可以一起使用它们。

What have I tried? 我尝试了什么?

I tried creating a QVector that stores QGraphicsItem type, but I got the result that it cannot store abstract class types. 我尝试创建一个存储QGraphicsItem类型的QVector ,但结果是它不能存储抽象类类型。 What should I do? 我该怎么办?

My plan 我的计划

My plan is to store these elements into QVector<T> member of a class timeline , because they will create a timeline. 我的计划是将这些元素存储到类timeline QVector<T>成员中,因为它们将创建时间轴。 For example: 例如:

class timeline : public QGraphicsScene // is this a good idea? to inherit QGraphicsScene?
{
private:
    QVector<QGraphicsItem*> items;
    int left_offset; // this is for putting the items next to each other
public:
    timeline();
    void add_item( QGraphicsItem *item );
    ~timeline();
}

My timeline should look like the sketch below: 我的时间轴应如下图所示:

在此处输入图片说明

So, when the user calls add_item() method, 因此,当用户调用add_item()方法时,

Timeline *timeline;
timeline->add_item( new ActivityItem( /* parameters */ ) ); // timeline->left_offset += 150;
timeline->add_item( new DeadTimeItem( /* parameters */ ) ); // timeline->left_offset += 100;

the left_offset increases depending on the type of the inserted item. left_offset随插入项目的类型而增加。

I know my post is quite long, but please read it completely, because I really need your help! 我知道我的帖子很长,但是请完整阅读,因为我真的需要您的帮助! Thank you! 谢谢!

As you've already guessed, I am using Qt. 正如您已经猜到的,我正在使用Qt。 I can also use boost if it is really necessary. 如果确实需要,我也可以使用boost。

You cannot create an instance of an abstract class, which is fortunate, because trying to assign a derived class to a base class provokes slicing or misbehaves in other interesting ways. 您不能创建一个幸运的抽象类的实例,因为尝试将派生类分配给基类会以其他有趣的方式引起切片或行为异常。

Due to the above restriction, no standard container for base can store a derived. 由于上述限制,没有用于base的标准容器可以存储派生对象。 You can circumvent this limitation by using pointers to base, either raw (non-owning) pointers or some smart-pointer type. 您可以通过使用指向基础的指针(原始(非所有权)指针或某些智能指针类型)来规避此限制。

The answer using the standard library would be something like: 使用标准库的答案将类似于:

std::vector<std::shared_pointer<QGraphicsItem>> v;

Using QT classes: 使用QT类:

QVector<QSharedPointer<QGraphicsItem>> qv;

Assuming 假设

  • QGraphicsItem objects are part of the same scene and have a parent QGraphicsItem对象是同一场景的一部分,并且具有父级
  • The list is tightly tied to the scene (member variable of the same class which owns the scene, or member variable of a scene subclass). 该列表与场景紧密相关(拥有场景的同一类的成员变量,或场景子类的成员变量)。

Then you should use this: 然后,您应该使用以下代码:

    QList<QGraphicsItem*> items; // or QVector or std::list, nearly same

These are raw pointers, they will not automatically delete the object when removed from list, nor will they get notified when item is deleted. 这些是原始指针,从列表中删除时它们不会自动删除对象,而在删除项目时也不会得到通知。 Still, I don't know of a smart pointer type, which would work with QGraphicsItem , so raw pointers are what you must use. 我仍然不知道可以与QGraphicsItem一起使用的智能指针类型,因此必须使用原始指针。 So if you need to also remove items dynamically, read on: 因此,如果您还需要动态删除项目,请继续阅读:


First of all, when you delete item, you need to also remove the pointer from this list, to avoid having dangling pointer. 首先,在删除项目时,还需要从列表中删除指针,以免指针悬空。 As an example, you may want to use something like QList::indexOf() and QList::removeAt() methods for this (also, if removal is very common and there are many items in the list, you may need to rethink the approach, as removing from an big array is slow). 举例来说,您可能想使用类似QList::indexOf()QList::removeAt()方法的方法(此外, 如果删除非常普遍并且列表中有很多项目,则可能需要重新考虑方法,因为从大型阵列中删除速度很慢)。 You need to be careful that item doesn't get deleted by some Qt code without you having a chance to remove it from the list. 您需要注意,如果没有机会从列表中将其删除,则该项目不会被某些Qt代码删除。

Things get more complicated, if you may have items in the list, which also have their children in the list. 如果您可能在列表中有项目,而列表中有他们的孩子,那么事情会变得更加复杂。 If you just delete an item, it will delete it's children, so if your list has pointers to these and your list will end up with dangling pointers to those children. 如果您只是删除一个项目,它将删除它的子项,因此,如果您的列表中有指向这些子项的指针,并且您的列表最终将带有指向那些子项的悬挂指针。 So, you need to do deletion very carefully. 因此,您需要非常小心地删除。 There are at least 3 different ways to go about this I can think of (recursive deletion in your own code, removing from list in item destructors, using event filter to catch item removals), so I can expand the answer, if this situation can happen in your code. 我可以想到的解决方法至少有3种(在您自己的代码中递归删除,从项目析构函数的列表中删除,使用事件过滤器捕获项目删除),因此,在这种情况下,我可以扩大答案发生在您的代码中。

Final note: when the entire scene is deleted, it will delete all its children. 最后说明:删除整个场景时,它将删除其所有子级。 Only thing you need to do here is make sure the pointers to deleted items in the list don't ever get used, for example simply by clearing the list. 您在这里要做的只是确保列表中已删除项目的指针永远不会被使用,例如,只需清除列表即可。

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

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