2011-09-16 31 views
1

我遇到以下設計問題:在定義自定義界面時繼承庫類

我正在爲應用程序使用Qt C++庫。在這個庫中有「模型」類,所有從QAbstractItemModel繼承(如QAbstractTableModelQStandardItemModel等)。我想從幾個這些類繼承,但是定義他們必須分享的我自己的接口。

我目前這樣做的方式是通過定義的接口(純虛類)並具有繼承的類從該繼承爲好。舉個例子,比方說我想要一個類從QAbstractTableModel繼承有doSomething功能:

class MyInterface { 
public: 
    virtual void doSomething() = 0; 
} 
class MyModel : public QAbstractTableModel, public MyInterface { 
    ... 
} 

不過,我只是想通過周圍對象爲一QAbstractItemModel。要使用接口類,我必須將它們轉換爲MyInterface對象,然後調用這些函數,這會導致在各處投射。此外,如果其他人讓自己的課程從QAbstractItemModel開始,那麼如果他們不繼承該接口,似乎也有錯誤的餘地。

是否有更好的設計,我可以使用來實現這一切?

回答

0

是。首先,根本不要使用MyInterface類。當你想採取任何具有doSomething()方法的對象時,使用模板。如果你是「繞傳遞對象作爲QAbstractModel」暗示你正在編寫一個接受類型QAbstractModel的任何對象的功能,其中有些可能不是爲MyModel的(甚至MyInterface的公司)。如果您調用doSomething,那麼您違反了函數接受QAbstractModel類型的任何對象的約定。

您使用哪種鑄造
+0

爲模板系統知道該對象有doSomething()方法它需要知道這個類是什麼東西比QAbstractTableModel無論如何,只需要QAbstractTableModel指針/引用(例如從Qt函數)是有效的 - 所以這根本不能解決問題 –

+0

MyInterface類根本沒有解決任何問題。甚至在有問題需要解決之前,它很可能會嘗試使用C++的所有功能。 –

+0

這是對我打破的合同的一個好想法。這讓我覺得我應該重新思考我在整個問題上的立場。 – buck

0

?如果你使用dynamic_cast,你的代碼看起來不會更好,但如果你總是檢查轉換結果的空值,那麼至少應該對非接口類可能出現的錯誤進行檢查。

這變得更爲複雜,當有大型組可能的類,如爲MyModel的監守你不能直接投(動態或靜態)從QAbstractTableModel到MyInterface的 - 你需要嘗試鑄造他們都以向下轉換接口稍後再上課。一個解決方案可能與一些模板把戲做到這一點 -

class MyInterface { 
public: 
    virtual void doSomething() = 0; 
} 

template <typename T> 
class MyTemplatedInterface: public T, public MyInterface { 
private: 
    virtual void foo(){}; // might be neceseary to be able to dynamic_cast to this type 
} 

class MyModel: public MyTemplatedInterface<QAbstractTableModel>{ 
public: 
virtual void doSomething(){}; 
} 

這樣,如果你得到QAbstractTableModel指針,並想知道,如果它實現MyInterface的,你只投給MyTemplatedInterface,不管實現類型是什麼實際的基礎。這個設計有一些缺陷,比如無法處理多個接口或者聲明模板類的構造函數 - 其中大多數將會在C++ 0x中被刪除,但是目前還沒有編譯器實現足夠的代碼來根據它來編寫代碼。

+0

Qt有[qobject_cast](http://doc.qt.nokia.com/stable/qobject.html#qobject_cast)可以解決直接投射的問題。這仍然是醜陋的。 – buck

+0

如果MyInterface不是繼承QObject(並且它不能繼承其他QObject-decendant,那麼qobject_cast將無法使用它)。 –