2016-03-08 92 views
7

在我一年的Qt編程中,我學到了很多關於信號和插槽的知識。但還不夠......公共功能與公共時隙

http://doc.qt.io/qt-5/signalsandslots.html

插槽可用於接收信號,但他們也都正常 成員函數。

所以......有什麼理由不申報的每一個功能,從QObject繼承,作爲一個槽,它是否需要是一個或不是一類?

在上面的鏈接,他們舉一個例子:

小基於QObject的級可能​​是:

#include <QObject> 

class Counter : public QObject 
{ 
    Q_OBJECT 

public: 
    Counter() { m_value = 0; } 

    int value() const { return m_value; } 

public slots: 
    void setValue(int value); 

signals: 
    void valueChanged(int newValue); 

private: 
    int m_value; 
}; 

爲什麼定義value()功能作爲一個普通的函數,而不是一個插槽?如果他們確實把它作爲一個插槽,會有什麼負面結果嗎?

回答

12

回到過去,如果你想連接信號,你別無選擇,只能使用插槽。在Qt 5中不再是這種情況,可以連接到常規成員函數甚至自由函數或lambda表達式。

聲明一個槽將那個函數註冊到該特定對象的元數據中,使得它可以被所有依賴元對象的Qt功能所使用。除此之外,它是文檔所述的常規成員函數。槽功能本身沒有什麼特別之處,不同之處在於在元對象中爲它生成元數據。

這意味着在編譯時間和可執行文件大小方面,聲明插槽都需要花費一定的代價,儘管很小。我認爲把所有的公共職能作爲插槽是矯枉過正的。只有在實際需要插槽時才使用插槽,如果它不能與常規功能一起工作,使其成爲插槽,效率會更高。

此外,請注意幾乎在所有情況下,信號都使用返回類型void進行聲明。這與信號的典型使用情況有關 - 它們通常可以傳遞參數,但很少返回任何信息。儘管可以通過連接到插槽的信號返回值,但這種情況極少發生。因此,聲明一個返回某個要插入的插槽的函數並沒有多大意義,因爲它返回一個值意味着它很可能不會在典型的信號/插槽上下文中使用。這就是爲什麼在這個例子中getter不是插槽。作爲插槽的setter在Qt 5中是多餘的,並且可能是此示例代碼的產品,可追溯到Qt 4.

最後,從常規公共職能中分離插槽是說明意圖的好方法,或「API 「如果你願意的話。例如,我在擴展QML時主要使用插槽,因此我不必將每個函數明確標記爲invokeable - 與上一段中提到的場景不同,這些插槽通常會返回內容,但它們並不真正用於連接。這樣我就清楚地瞭解了該類所提供的接口的設計。

-1

對於某些功能,您需要一個返回值。這不會在插槽中輕鬆工作。在槽中,你不能使用函數的返回值或給它們一個參考參數。是的,你可以做到這一點,但你有一個時間問題。 無論您是在軟件架構上使用插槽還是正常的成員函數依賴項,

另外,插槽在事件循環中運行。如果這是有意或無意的,它取決於你的代碼。

+1

這個答案沒有絲毫意義,甚至沒有解決這個問題。 – MrEricSir

+0

您可以在插槽中使用返回值嗎?或者甚至以正確的方式獲取參考參數的值? – SuperFliege

+1

@SuperFliege - 插槽只是一個函數,它的功能與函數完全相同。多線程和對象生命週期是完全不同的問題,並影響正常功能,就像它們影響插槽一樣。 – dtech

2

除了ddriver的回答,這是最好的/正確的答案(在那裏+1),我還會爭辯說定義所有成員函數爲公開槽是混淆的。他們定義功能(私人/公共/插槽等)的方式會影響班級的感知使用。

我的意思是......你可以說所有的功能都應該是公開的(或公開的插槽),然後涵蓋所有的情況。然而,這可能會讓您班級的未來用戶感到困惑。考慮到int value()是一個公共插槽(它不是最好的例子),有人可以嘗試使用它作爲一個,但函數本身具有返回值,這對於插槽來說並不合適。它對於一個正常的成員函數來說是有意義的,在該函數中可以訪問返回值(作爲正常函數調用)。

要遵循的一條規則是始終保持您的函數和變量爲局部作用域和私有角色(默認情況下),並且只爲其他用途(public-ness,slots,global等)打開它們。 )當你真的需要他們。這使您的類界面更容易理解,並避免以後用戶感到困惑。

我肯定是這個規則的拇指的名稱,所以你可以看看它的一些編碼技術的網站,但我不記得它:(

編輯

另一個小例子是自動完成...如果你所有的功能都是插槽,那麼當你正在做你的自動完成選項的列表可能會很長並且不清楚是什麼。如果你只有幾個特定的​​成員是插槽那麼它更容易知道選哪個。

+1

您正在尋找的術語是封裝。 – thuga

+0

@thuga - 是封裝絕對是主題......但我確定有一些「規則名稱」用於保持一切最小範圍....也許它只是「封裝規則」?:o謝謝:) –

+0

我唯一要添加到這個答案的是公共插槽是Q_INVOKABLE,並且您可能不希望所有公共方法都可以從QML上下文訪問。 – MrEricSir

2

在參考enca從code_fodder的答案來看,應該指出的是,真的沒有私人插槽這樣的東西。

例如:

class MyClass : public QObject 
{ 
    Q_OBJECT 
public: 
    MyClass() 
     :QObject(NULL) {} 

private slots: 
    void Hello() { qDebug("Hello World\n"); } 
}; 

#include "main.moc" 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    MyClass* cls = new MyClass; 
    QMetaObject::invokeMethod(cls, "Hello"); 

    return a.exec(); 
} 

正如我們所看到的,調用該函數Hello是從類的外部成功。

+0

它也適用於連接嗎?順便說一句,調用私有函數的可能性完全在Qt上,沒有訪問檢查。私人插槽是非常真實的,即使不被meta系統所尊重:) – dtech

+0

是的,如果你通過舊的連接方法(pre Qt 5)連接,使用SIGNAL,SLOT宏。例如用QTimer *連接(pTimer,SIGNAL(timeout()),cls,SLOT(Hello())); * – TheDarkKnight

+1

@TheDarkKnight它是一個非常有趣的觀察(+1分享)。當我在同一個班級建立內部連接時,我總是使用私人插槽,否則......但我從來沒有想過要檢查(或注意)Qt不會妨礙私人插槽的可見性! - 仍然,這不會改變我定義它們的方式,因爲即使Qt是寬鬆的(或只是錯誤在這裏)我不喜歡:) –

0

您不希望所有方法都是插槽的另一個用例是,您將對象通過Qt's WebKit Bridge公開時段: 可通過JavaScript調用所有公用插槽。

所以如果你想要一個不能從JavaScript調用的公共方法,你不能聲明它是一個插槽。

+0

我的問題的主要原因是因爲我必須向JavaScript公開對象 - 並且使用應用程序特定方面的人員非常高興地要求幾乎每個函數都可以成爲一個插槽。我想限制這個......但我需要一個原因。對於返回值的函數,這些函數可以通過使它們成爲'Q_PROPERTY'來成爲JavaScript的可調參數。 – Thalia