2013-12-11 18 views
0

我在程序中使用了observer-observable模式。一切工作之前,我不得不稍微更改代碼。如果是準確的,我改變IObserver類的繼承 - 現在它繼承自QObject:因爲訪問deleteLater()方法而導致的QObject的多重繼承

class IObserver : public QObject 
{ 
... 

我這樣做是因爲只有一件事 - 我需要deleteLater()方法以觀察員使用,所以我會能夠調用IObserver的虛函數deinitialization()的實現。因此我可以標準化每個IObserver消息處理程序。

問題是,我已經在某些Observer類中繼承了QObject(間接)。像MainForm或AboutDialog一樣。一切都很好,直到我嘗試在AboutDialog類中調用「connect」方法。

我該怎麼辦?我真的需要這個deleteLater()方法,因爲我不能在IObserver代碼中使用「delete this」 - 這將調用IObserver析構函數,而不是MainForm或Storage類。

謝謝。

+0

也許在這裏提示:[http://stackoverflow.com/questions/3259728/using-qt-signals-and-slots-with-multiple-inheritance](http://stackoverflow.com/questions/3259728/使用-qt-signals-and-slots-with-multiple-inheritance) – jbh

回答

1

我真的需要這個deleteLater()方法,因爲我不能在IObserver代碼中使用「delete this」 - 這會調用IObserver析構函數,而不是MainForm或Storage類。

如果你使你的析構函數爲虛擬的(你應該!)它會調用派生析構函數。但問題在於,在處理某個信號/插槽時破壞對象可能會導致事件循環出現問題。無論如何,你必須非常小心delete this

問題是,我已經在一些Observer類中繼承了QObject(間接)。您可以實現這一點,不知道最好的思想

方式一:

template <typename Derived> 
class IObserver 
{ 

    // Just to be sure: (C++11) 
    static_assert(is_base_of<Derived, QObject>::value, 
        "must inherit from QObject when using IObserver"); 

    void deleteMe() 
    { 
     QObject* thisObject = dynamic_cast<QObject*>(this); 
     // no need for check if thisObject equals null. static assert does this. 
     thisObject->deleteLater(); 
    } 

}; 

class MainForm : public IObserver<MainForm>, public QMainWindow 
{ 
    // ... 
}; 

我相信這種模式稱爲靜態多態性。

+0

**如果你使你的析構函數虛擬(你應該!)** 我在IObserver中使用'virtual void deinitialisation()= 0',並相信在實現的版本中所有的資源都會被釋放,所以在調用deinit我想刪除該對象。謝謝你的例子,我明天會試一試。 –

+0

問題是如果有人決定'刪除anIObserverPointer',它不會清除派生類的資源。另外,爲什麼不把代碼從'deinitialization()'移動到'〜IObserver()'?更安全。 –

0

爲IObserver放棄繼承QObject。而不是添加這種方法來接口。

class IObserver : public QObject { 
public: 
    QObject *object() const = 0; 
... 

那麼,如果實現的接口繼承QObject,你會從object()方法返回this指針。如果接口的實現不會繼承QObject,則可以簡單地將指針返回到一些簡單的QObject,它將處理此對象的銷燬。 然後你可以簡單地連接deleteLater這個方法返回的對象。

題外話
在Qt的觀測使用的接口通常是過時的,插槽和信號完美地做好這項工作,這是更靈活的方法。

+0

>完美工作 並非在任何情況下。當需要將所有可能的信號寫入日誌時,需要將這些信號連接至不標準化的日誌功能。我使用3參數通用函數(與Windows的SendMessage一樣),而不是使用20-30個函數。另外,我可以完全刪除觀察者,而不會損壞應用程序。而不是調用特定的函數,例如profileManager.getProfilesList,我調用Send(OC_PROFILEMNGR,MC_GETPRFNAMES,&myStringList)。所以我不在乎是否有像getProfileList這樣的函數,或者即使存在這樣的管理器。 –