2010-09-08 120 views
14

雖然審查我碰到這個就一些Qt的C++代碼:虛擬Qt信號?

class Foo 
{ 
    Q_OBJECT 

signals: 
    virtual void someSignal(const QString& str, int n) 
    { 
    Q_UNUSED(str); 
    Q_UNUSED(n); 
    } 
    ... 
}; 

現在,Qt的信號不能有身體,所以我很驚訝這甚至編譯(或許是因爲身體有效地爲空)。我也沒有看到讓虛擬信號變成虛擬的點......它不能有一個身體,所以它怎麼可能被覆蓋?

我在這裏錯過了什麼,或者這是一個有效的代碼氣味?

回答

15

這看起來很臭。

在基類中聲明信號然後從派生類中發出信號是有效的,例如,

class MyBase : public QObject 
{ 
    Q_OBJECT 
// ... 
signals: 
    void somethingHappened(); 
}; 

class MyDerived : public MyBase 
{ 
    Q_OBJECT 
// ... 
    void doSomething(); 
}; 

void MyDerived::doSomething() 
{ 
    // .... 
    emit somethingHappened(); 
} 

也許這就是問題中的聲明所要達到的目的。

4

嚴格的C++說這是正常的編譯,給出signal是一個宏爲protectedQ_UNUSED是演員void。 但是,運行moc時應該會出錯,它會精確地創建聲明爲信號的方法的實現。

+2

它可以編譯,但它仍然是一個ODR違規:函數有兩個主體,一個在頭中,另一個在moc發出的cpp中。 – ybungalobill 2015-10-27 12:18:24

2

TL; DR:我不知道代碼是做什麼的,但它是錯誤的(不只是嗅到錯誤,它的表面看起來無效)。信號實現是總是意味着由moc生成。信號的主體應該被刪除。

  1. 對於代碼的工作,它應該做的所有三個:編譯,通過moc和鏈接。確實,您的代碼確實會編譯 - C++編譯器沒有理由不這樣做。但它不會通過moc,也不會鏈接。

  2. 雖然也許MOC沒有在2010年發現了一些回來,這裏是如何MOC行爲今天:

    一)MOC不允許在類主體的信號定義,與診斷Error: Not a signal declaration。所以class X { Q_SIGNAL void s() {} };觸發它,但class X { Q_SIGNAL void s(); }; void X::s() {}不會。

    B)MOC不允許Q_OBJECT宏在一個類不是從QObject導出,與所述診斷Error: Class contains Q_OBJECT macro but does not inherit from QObject

  3. 因爲它沒有任何意義,談論類信號不從QObject派生,讓我們假設代碼確實看起來如下:

    class Foo : public QObject 
    { 
        Q_OBJECT 
    signals: 
        virtual void someSignal(const QString&, int); 
    }; 
    void Foo::someSignal(const QString& str, int n) 
    { 
        Q_UNUSED(str); 
        Q_UNUSED(n); 
    } 
    

    這將讓過去的交通部將編譯,但它不會鏈接。鏈接器將爲多個聲明Foo::someSignal發出診斷。這個文件中有一個定義,另一個定義在moc生成的源文件中。