对于我继承自QGraphicsLineItem
,QGraphicsRectItem
等的几个图形对象。
class CustomLine : public QGraphicsLineItem{};
class CustomRect : public QGraphicsRectItem{};
这些对象被添加到容器中,容器是QGraphicsScene "scene"
的自定义子类,用于显示和与这些项进行交互。 this->scene->items()
会返回QGraphicItem
的列表:QList<QGraphicsItem* >
我想要做的是每个自定义对象类具有相同的自定义接口方法,例如setModeX()
。然后我可以做类似的事情:
Foreach (BaseItem *item, this->scene->items()){
item->setModeX(...);
}
但我该如何实现呢? 如果我创建一个像
这样的界面class BaseItem{
public: setModeX(); [...]
private: Mode mode_;
}
并继承
class CustomLine : public QGraphicsLineItem, BaseItem {};
因此,虽然场景应该只包含基于BaseItem
的项目(不确定这个任务是否真的需要),但我首先检索其2个基类之一的对象列表,即{{1并且需要将其强制转换为其他基类QGraphicsItem
以使用接口方法。
我可能无法在上面的循环中将CustomLine项转换为BaseItem,因为它不知道其他基类。
编辑:
我使用MinGW 4.8 32位(g ++)。
我注意到,当我开始foreach循环时,我场景中的项目消失了(但没有看到原因)
答案 0 :(得分:0)
应该工作正常,但记得在基类中声明接口方法是虚拟的,至少如果你想要多态行为。
答案 1 :(得分:0)
将要在每个派生类中存在的函数声明为基类中的虚函数。在基类中定义为虚函数的函数可以提供默认实现,但派生类可以自由地覆盖该实现并提供它们自己的实现。你也可以声明这个功能&#34;纯粹的虚拟&#34;这意味着派生类必须为该特定函数提供实现。
在任何一种情况下,当在基类的指针指向的实例化对象上调用该函数时,它会注意到基类将该函数声明为虚拟并使用虚拟表(vtable)来查找哪个函数调用(如在基类&#39;函数定义中,如果存在,或函数的派生类版本)。
答案 2 :(得分:0)
似乎对你的问题有一些限制,使这更像是一个问题。如果您无法控制scene
中的基础指针,但是您知道每个项都继承自BaseItem
,那么您可以在for循环中进行强制转换。
例如,使用上面的结构:
Foreach (QGraphicsItem *item, this->scene){
((BaseItem*) item)->setModeX(...);
}
当然,只有当您可以保证场景中的对象来自BaseItem
时,才会这样做。
答案 3 :(得分:0)
由于scene
是QGraphicsScene
,因此它只包含QGraphicsItem
个。因此,您无法直接在代码中显示scene
作为BaseItem
进行迭代。你必须迭代每个QGraphicsItem
。您描述可以向下转换为CustomLine
,然后向上转发回BaseItem
,但只有当您知道scene
中的所有项目都是行时,这才有效。如果scene
包含其他类型的项目,那么您的技术将要求您对每种项目进行迭代,直到找到有效的向下转换为止,然后将其转发回BaseItem
。
QGraphicsItem
\ BaseItem
QGraphicsLineItem /
\ /
CustomLine
如果Qt库在QGraphicsItem
上使用了虚拟继承,那么您可以使用一个简单的解决方案。然后,您只需要在QGraphicsItem
BaseItem
上使用虚拟继承,然后向下转换就可以了。
QGraphicsItem
/ \
QGraphicsLineItem BaseItem
\ /
CustomLineItem
由于Qt没有这样做,您需要对Qt库进行自定义更改,或者在您自己的转换机制中进行编码。
假设您不愿意对Qt库本身进行自定义修改,那么一种方法是在Qt的QGraphicsItem
和您的BaseItem
之间创建映射。映射可以在BaseItem
的构造函数中完成,也可以从BaseItem
的析构函数中撤消。要更有效地撤消映射,您还可以创建从BaseItem
到QGraphicsItem
的链接。
class BaseItem {
static std::unordered_map<QGraphicsItem *, BaseItem *> map;
QGraphicsItem *link_;
public:
BaseItem (QGraphicsItem *q) : link_(q) {
//...
map[q] = this;
}
virtual ~BaseItem () {
map.erase(link_);
//...
}
static BaseItem * getBaseItem (QGraphicsItem *q) {
std::unordered_map<QGraphicsItem *, BaseItem *>::iterator i;
if ((i = map.find(q)) == map.end()) return NULL;
return i->second;
}
//...
};
//...
std::unordered_map<QGraphicsItem *, BaseItem *> BaseItem::map;
在派生类中,您只需将this
传递给BaseItem
构造函数。
class CustomLine : public QGraphicsLineItem, public BaseItem {
public:
CustomLine () : BaseItem(this) {
//...
};
//...
};
然后你的循环将使用静态BaseItem::getBaseItem()
函数将QGraphicsItem
指针转换为BaseItem
指针。因此,由于无法在QGraphicsItem
和BaseItem
之间创建可用的继承关系,因此它们的关系将记录在表中。
QGraphicsItem <-----------------. link
\ BaseItem <--' map
QGraphicsLineItem /
\ /
CustomLine
答案 4 :(得分:0)
CRTP救援:
template <class D> class Base {
D& m_d;
public:
Base(D& derived) : m_d(d) { ... }
...
};
class CustomLine : public QGraphicsLine, Base<CustomLine> {
...
CustomLine() : Base(*this) { ... }
};