2016-04-27 9 views
1

私はもう一度QObjectの制限に遭遇しましたが、テンプレートと混合できません(少なくとも直接ではありません)。基本的に私は、インデックスを使用してソース位置をローカル位置に変換し戻すプロキシモデルクラスを用意しています。インデックスはいくつかの方法で実装できます.2つのバージョンが必要です.1つはQHashを使用し、もう一方はQVectorを使用します。インデックスのインターフェイスは、インデックス操作に関する微妙な違いだけで、両方に共通です。テンプレートを使用すると、これは簡単にできます。クラスをテンプレートにして、これらの2つのケースで特殊化を使用します。モデル内での仮想インデックスの実装の代替

モデルがQObjectにする必要があるしかしその代わりに、私がそうのような多型を使用する必要がありそうです:

class IndexInterface; 
class VectorIndex; //inherits IndexInterface 
class HashIndex; //inherits IndexInterface 

class ProxyModel : public QObject 
{ 
    Q_OBJECT 
public: 
    enum IndexType { Vector, Hash }; 

    explicit ProxyModel(IndexType indexType, QObject *parent = 0) : 
     QObject(parent), 
     index(indexType == Vector ? new VectorIndex : new HashIndex) 
    { 
    } 
    //... 

private: 
    IndexInterface *index = nullptr; 
}; 

私はこれで問題のカップルを持っています。まず、私が取り除きたいインデックスの動的割り当てが必要です。第2に、IndexInteraceへのポインタの使用のために、インデックスへの呼び出しをインライン化することはありません(私はこれを確認するためにコードを逆アセンブルし、様々な最適化などを試みました)。

インデックスを動的に割り当てることなく、インデックスを仮想的に呼び出すことなく、このデザインに代わるものは何でしょうか?

答えて

2

インデックス型固有のクラス基底クラスの1つ作成します:

QAbstractItemModel * proxyFactory(IndexType indexType, QObject * parent = 0) { 
    switch (indexType) { 
    case Foo::Vector: 
    return new VectorIndexProxy(parent); 
    ... 
    } 
} 

あなたの場合:次に

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よりも幅広いインターフェースを想定している場合は、そのような基本クラスを作成し、具体的な実装でそれから派生する必要があります。

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 
}; 

信号とスロットを持つ基本非QObjectクラスを持つことについては、this questionを参照してください。

最後に、PIMPL idiomを使用して、必要に応じて固定タイプの具体的な実装を行うことができます。ファクトリはコンストラクタで呼び出され、異なるインデックスの異なるPIMPLを交換します。 以降のすべてのQtクラスは、既に動的にPIMPLを割り当てているので、PIMPLをQObjectPrivate#include <private/qobject_p.h>)から派生させ、保護されたQObject(QObjectPrivate&)にPIMPLのインスタンスを渡すことによって、その割り当てをピギーバックすることができます。このパターンはQtに遍在しているので、実装の詳細であっても、少なくともQt5ではそれほど遠くには通りません。ここではラフスケッチです:

// 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生まれのクラスで動作します!

+0

最初の例の 'VectorIndexProxy'と' HashIndexProxy'クラス定義に 'Q_OBJECT'マクロを必ず含めてください。 –

+0

@JonHarperこれは '...'に暗示されていることです:)そうでなければ、それは滑りやすい斜面です。誰かが私に教えてくれる次のものは、モデルの全体的な正しい実装がそこに属しているということです: –

+0

良い点。 :-) –

関連する問題