多个继承和接口方法
Multiple inheritance and interface methods
对于我从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
的项(不确定此任务是否真的需要),但我首先检索它的两个基类之一(即QGraphicsItem
)的对象列表,并需要将其强制转换为它的另一个基类BaseItem
以使用接口方法。在上面的循环中,我可能无法将CustomLine项强制转换为BaseItem,因为它不知道其他基类。
编辑:
我使用MinGW 4.8 32位(g++)。
我注意到,当我开始foreach循环时,场景中的项目会消失(但看不出原因)
由于scene
是一个QGraphicsScene
,它只由QGraphicsItem
s组成。因此,您无法直接将scene
迭代为代码中显示的BaseItem
s。您必须对每个QGraphicsItem
进行迭代。您描述了可以向下转换到CustomLine
,然后向上转换回BaseItem
,但只有当您知道scene
中的所有项目都是行时,这才有效。如果scene
包含其他类型的项,那么您的技术将要求您迭代每种项,直到找到一个有效的下转换,然后将其强制转换回BaseItem
。
QGraphicsItem
BaseItem
QGraphicsLineItem /
/
CustomLine
如果Qt库在QGraphicsItem
上使用了虚拟继承,那么您就可以使用一个简单的解决方案。然后,您只需要从BaseItem
对QGraphicsItem
使用虚拟继承,然后向下转换就可以了。
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
应该可以正常工作,但请记住在基类中声明接口方法是虚拟的,至少如果您想要多态行为的话。
将希望存在于每个派生类中的函数声明为基类中的虚拟函数。基类中定义为虚拟的函数可以提供默认实现,但派生类可以自由覆盖该实现并提供自己的实现。您还可以将该函数声明为"纯虚拟",这意味着派生类必须为该特定函数提供实现。
在任何一种情况下,当对基类指针指向的实例化对象调用该函数时,它都会注意到基类将该函数声明为虚拟的,并使用虚拟表(vtable)来查找要调用的函数(如基类对函数的定义(如果存在)或函数的派生类版本)。
您的问题似乎受到了一些限制,使其变得更像一个问题。如果您不能控制scene
中的底层指针,但您知道这些项中的每一项都继承自BaseItem
,那么您可以在for循环中执行强制转换。
例如,使用上面的结构:
Foreach (QGraphicsItem *item, this->scene){
((BaseItem*) item)->setModeX(...);
}
当然,这只是在您可以保证场景中的对象是从BaseItem
派生的情况下。
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) { ... }
};
- 类接口,可以创建N个方法
- 如何使用接口指针调用方法,该指针是其具体类的一部分,而不是接口的一部分
- C++接口继承不同的参数方法
- 并发安全堆栈接口方法:正确与否?
- 无法将__str__特殊方法与Boost::Python接口
- 正在接口构造函数中调用重写的接口方法
- 接口描述中接口方法的预定义参数列表
- C++对象作为接口方法的参数
- 多个继承和接口方法
- COM属性方法和常规接口方法之间的区别是什么
- 公共接口方法的私有实现
- 接口方法的实现
- 如何使用c#中的参数BSTR*和BSTR**来调用遗留的c++ DLL接口方法?
- 接口方法并返回指向this (enable_shared_from_this)的智能指针
- c++回调非静态接口方法
- 在VS2012中调用接口方法导致指针不完整
- 对VB6接口方法的后期绑定调用
- COM接口方法限制
- 为什么 CRTP 实现和接口方法的名称不同
- 如何在c++ Builder中解决接口方法和基类方法名称冲突?