使特定于索引类型的类成为基类之一:
template <typename Index> class IndexHandler {
};
using VectorIndexHandler = IndexHandler<QVector>;
using HashIndexHandler = IndexHandler<QHash>;
class VectorIndexProxy : public QAbstractItemModel, VectorIndexHandler {
... // should be very small
};
class HashIndexProxy : public QAbstractItemModel, HashIndexHandler {
... // should be very small
};
那么不要将索引类型传递给构造函数,而是使用工厂函数:
QAbstractItemModel * proxyFactory(IndexType indexType, QObject * parent = 0) {
switch (indexType) {
case Foo::Vector:
return new VectorIndexProxy(parent);
...
}
}
如果您设想一个比QAbstractItemModel 更广泛或不同的接口,您当然需要编写这样一个基类并在具体实现中从它派生。
如果IndexHandler 需要,您可以使用 CRTP 直接调用派生类的方法,使其更小:
template <typename Index, typename Derived> class IndexHandler {
Derived * derived() { return static_cast<Derived*>(this); }
const Derived * derived() const; // as above
void foo() {
derived()->setObjectName("Yay");
}
};
class VectorIndexProxy :
public QAbstractItemModel,
public VectorIndexHandler<QVector, VectorIndexProxy>
{
... // should be very small
};
您还可以将基类中的方法“提升”为 Qt 插槽:
class VectorIndexProxy : ... {
#ifdef Q_MOC_RUN
Q_SLOT void foo();
#endif
};
请参阅this question,了解如何使用带有信号和槽的非 QObject 基类。
最后,您可以使用PIMPL idiom,并根据您的需要拥有一个固定类型的具体实现。工厂将在构造函数中调用,您将在不同的 PIMPL 中交换不同的索引。这并不像您想象的那么昂贵,因为所有 Qt 类都已经动态分配了 PIMPL,因此您可以通过从 QObjectPrivate (#include <private/qobject_p.h>) 派生 PIMPL 并传递PIMPL 的实例到受保护的QObject(QObjectPrivate&)。这种模式在 Qt 中无处不在,所以即使它是一个实现细节,它至少在 Qt 5 中并没有消失。这是一个粗略的草图:
// ProxyModel.cpp
#include <private/qobject_p.h>
class ProxyModelPrivate : public QObjectPrivate {
// Note: you don't need a q-pointer, QObjectData already provides it
// for you! CAVEAT: q-pointer is not valid until the QObject-derived-class's
// constructor has returned. This would be the case even if you passed
// the q-pointer explicitly, of course.
...
}; // base class
class VectorProxyModelPrivate : public ProxyModelPrivate { ... };
class ProxyModel : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(ProxyModel)
ProxyModel * pimpl(IndexType indexType) {
switch (indexType) {
case Vector: return new VectorProxyModelPrivate();
...
}
public:
enum IndexType { Vector, Hash };
explicit ProxyModel(IndexType indexType, QObject *parent = 0) :
QObject(*pimpl(IndexType), parent)
{}
};
如果您从QAbstractItemModel 派生,您的PIMPL 将以同样的方式从QAbstractItemModelPrivate 派生;这适用于 Qt 中的任何 QObject-deriving 类!