關(guān)于Qt?C++中connect的幾種寫(xiě)法代碼示例
前言
這connect函數(shù)就像是編程世界里的“茴”字,千變?nèi)f化,各有千秋。咱們程序員呢,就像是孔乙己那樣,雖然有時(shí)候會(huì)覺(jué)得這些變化有些好笑,甚至有些令人頭疼,但說(shuō)到底,還不是得乖乖地學(xué)著、用著,畢竟這可是編程里的“必備技能”。connect的編寫(xiě)每個(gè)人都有自己的習(xí)慣,也有其特點(diǎn),還是要深究一下的。
在Qt中,connect函數(shù)用于將信號(hào)(signal)與槽(slot)連接起來(lái),以便在信號(hào)被發(fā)射時(shí)自動(dòng)調(diào)用槽函數(shù)。Qt提供了幾種不同的connect寫(xiě)法,以及定義槽函數(shù)的方式,它們各有特點(diǎn)和適用場(chǎng)景。
1. 傳統(tǒng)的槽函數(shù)寫(xiě)法
在傳統(tǒng)的Qt項(xiàng)目中,槽函數(shù)通常是在類的頭文件中使用slots:關(guān)鍵字聲明的特殊成員函數(shù)。例如:
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots: // 使用slots關(guān)鍵字聲明槽函數(shù)
void onCalculateClicked();
// ... 其他成員和槽函數(shù) ...
};然后在源文件中實(shí)現(xiàn)這個(gè)槽函數(shù):
void MainWindow::onCalculateClicked() {
// 槽函數(shù)的實(shí)現(xiàn)
}使用這種寫(xiě)法時(shí),conect函數(shù)通常這樣調(diào)用:
connect(pbt, SIGNAL(clicked()), this, SLOT(onCalculateClicked()));
這里使用的是SIGNAL()和SLOT()宏來(lái)將信號(hào)和槽轉(zhuǎn)換為字符串形式的標(biāo)識(shí)符。
2. 使用函數(shù)指針的connect寫(xiě)法(5.0)
在5.0及后續(xù)的Qt版本中,推薦使用函數(shù)指針的connect寫(xiě)法,因?yàn)樗峁┝烁玫念愋蜋z查和編譯時(shí)錯(cuò)誤檢測(cè)。這種寫(xiě)法不需要使用slots:關(guān)鍵字或SIGNAL()/SLOT()宏,而是直接使用函數(shù)指針。例如:
connect(pbt, &QPushButton::clicked, this, &MainWindow::onCalculateClicked);
在這種寫(xiě)法中,&QPushButton::clicked是信號(hào)clicked的函數(shù)指針,&MainWindow::onCalculateClicked是槽函數(shù)的函數(shù)指針。編譯器會(huì)在編譯時(shí)檢查這些指針是否匹配。這種寫(xiě)法的優(yōu)點(diǎn)如下:
類型安全:
函數(shù)指針的connect寫(xiě)法提供了編譯時(shí)的類型檢查。這意味著如果信號(hào)和槽的函數(shù)簽名不匹配,或者指定的函數(shù)不存在,編譯器會(huì)立即給出錯(cuò)誤提示。這大大減少了運(yùn)行時(shí)錯(cuò)誤的可能性,因?yàn)樗械倪B接都是在編譯時(shí)驗(yàn)證的。易于閱讀和維護(hù):
使用函數(shù)指針使得代碼更加直觀和易于理解。你可以直接看到哪個(gè)信號(hào)被連接到了哪個(gè)槽,而不需要通過(guò)字符串來(lái)間接表示。這有助于代碼的維護(hù)和調(diào)試,因?yàn)槟憧梢愿菀椎馗櫺盘?hào)和槽之間的連接關(guān)系。自動(dòng)處理函數(shù)重載:
當(dāng)存在多個(gè)重載的信號(hào)或槽函數(shù)時(shí),使用函數(shù)指針可以自動(dòng)選擇正確的重載版本。傳統(tǒng)的SIGNAL()和SLOT()宏在處理重載函數(shù)時(shí)可能會(huì)遇到問(wèn)題,因?yàn)樗鼈円蕾囉诤瘮?shù)名的字符串表示,無(wú)法區(qū)分重載的函數(shù)。而函數(shù)指針則包含了函數(shù)的完整簽名,因此可以準(zhǔn)確地選擇所需的函數(shù)。提高性能:
雖然性能差異可能不是非常顯著,但使用函數(shù)指針的connect寫(xiě)法可能比使用字符串的宏稍微快一些。這是因?yàn)楹瘮?shù)指針可以直接在編譯時(shí)解析和連接,而不需要在運(yùn)行時(shí)進(jìn)行字符串比較和查找。與現(xiàn)代C++標(biāo)準(zhǔn)兼容:
隨著C++標(biāo)準(zhǔn)的不斷發(fā)展,使用函數(shù)指針的connect寫(xiě)法更符合現(xiàn)代C++的編程風(fēng)格。它利用了C++11及更高版本中的特性,如lambda表達(dá)式和智能指針,使得Qt的代碼可以與這些現(xiàn)代特性更好地集成。減少宏的使用:
減少宏的使用可以降低代碼的復(fù)雜性和潛在的錯(cuò)誤。宏在C++中經(jīng)常是導(dǎo)致難以調(diào)試的問(wèn)題的源頭,因?yàn)樗鼈兪窃陬A(yù)處理階段展開(kāi)的,而不是在編譯階段進(jìn)行類型檢查的。使用函數(shù)指針可以避免這些問(wèn)題。
3. Lambda表達(dá)式作為槽函數(shù)(C++11)
在C++11以后,除了傳統(tǒng)的槽函數(shù)和函數(shù)指針,Qt還支持使用Lambda表達(dá)式作為槽函數(shù)。這種寫(xiě)法非常靈活,因?yàn)樗试S你在connect調(diào)用中直接編寫(xiě)槽函數(shù)的代碼,而不需要在類中定義額外的成員函數(shù)。例如:
connect(pbt, &QPushButton::clicked, this, [this]() {
// Lambda表達(dá)式作為槽函數(shù)的實(shí)現(xiàn)
bool isOK;
double r = lEdit->text().toDouble(&isOK);
if (isOK && r >= 0) {
lab2->setText(QString::number(AreaCircal(r)));
} else {
lab2->setText("請(qǐng)輸入合法的半徑!");
}
});這種寫(xiě)法的優(yōu)點(diǎn)如下:
捕獲或引用捕獲的方式來(lái)控制這些變量的生命周期和作用域。
靈活性和動(dòng)態(tài)性:
Lambda表達(dá)式提供了一種靈活的方式來(lái)定義槽函數(shù)的行為。你可以在connect調(diào)用中直接編寫(xiě)Lambda表達(dá)式,而不需要事先在類中聲明槽函數(shù)。這使得你可以根據(jù)需要在運(yùn)行時(shí)動(dòng)態(tài)地定義槽函數(shù)的行為。減少代碼量:
使用Lambda表達(dá)式作為槽函數(shù)可以減少需要編寫(xiě)的代碼量。你不需要為每個(gè)槽函數(shù)都聲明一個(gè)成員函數(shù),這不僅可以減少代碼量,還可以使代碼更加緊湊和易于管理。類型安全:
與傳統(tǒng)的字符串宏相比,使用Lambda表達(dá)式作為槽函數(shù)提供了更好的類型安全。編譯器會(huì)在編譯時(shí)檢查L(zhǎng)ambda表達(dá)式的類型是否與信號(hào)的參數(shù)類型匹配,從而避免了運(yùn)行時(shí)錯(cuò)誤。
除了第一種傳統(tǒng)寫(xiě)法外,現(xiàn)在較為流行的二、三種寫(xiě)法對(duì)比分析如下:
| 特性 | Lambda表達(dá)式 | 函數(shù)指針 |
|---|---|---|
| 引入時(shí)間 | C++11 | C++早期版本、Qt5.0 |
| 定義方式 | 匿名函數(shù),直接在代碼中定義 | 需要顯式聲明和定義函數(shù),然后通過(guò)函數(shù)指針指向該函數(shù) |
| 語(yǔ)法簡(jiǎn)潔性 | 簡(jiǎn)潔,直接在調(diào)用處定義 | 相對(duì)繁瑣,需要額外的函數(shù)聲明和定義 |
| 類型推斷 | 支持,編譯器可根據(jù)上下文推斷類型 | 不支持,需要顯式指定函數(shù)返回類型和參數(shù)類型 |
| 捕獲外部變量 | 可以捕獲外部作用域中的變量 | 無(wú)法直接捕獲外部變量,只能訪問(wèn)函數(shù)參數(shù) |
| 執(zhí)行環(huán)境 | 在新的棧幀中執(zhí)行,具有獨(dú)立的調(diào)用環(huán)境和??臻g | 指向已存在的函數(shù),不擁有獨(dú)立的??臻g |
| 靈活性 | 適用于簡(jiǎn)單的、單行表達(dá)式的場(chǎng)合,易于在需要的時(shí)間和地點(diǎn)實(shí)現(xiàn)功能閉包 | 適用于調(diào)用已經(jīng)定義好的函數(shù),支持動(dòng)態(tài)綁定和回調(diào)函數(shù) |
| 代碼重用性 | 通常用于一次性或短暫的函數(shù)定義,代碼重用性較低 | 可以通過(guò)函數(shù)指針在不同位置調(diào)用同一函數(shù),代碼重用性較高 |
| 類型安全性 | 類型安全,編譯器檢查函數(shù)簽名 | 類型安全性較低,容易出現(xiàn)類型不匹配的問(wèn)題 |
| 性能 | 現(xiàn)代編譯器優(yōu)化后性能損失可忽略,但在某些情況下可能帶來(lái)輕微開(kāi)銷 | 通常性能開(kāi)銷較低,但間接調(diào)用可能帶來(lái)一些額外開(kāi)銷 |
| 使用場(chǎng)景 | 適用于需要定義簡(jiǎn)單匿名函數(shù)的場(chǎng)景,如STL算法中的排序和過(guò)濾 | 適用于需要?jiǎng)討B(tài)調(diào)用不同函數(shù)或?qū)崿F(xiàn)回調(diào)函數(shù)的場(chǎng)景,如事件處理、插件系統(tǒng)等 |
上述三種方法的特點(diǎn)和區(qū)別總結(jié):
- 傳統(tǒng)槽函數(shù):易于閱讀和維護(hù),特別是在槽函數(shù)邏輯復(fù)雜或需要多次重用的情況下。但是,它們?cè)黾恿祟惖膹?fù)雜度,因?yàn)樾枰陬^文件中聲明槽函數(shù)。
- 函數(shù)指針的connect:提供了更好的類型安全性,減少了運(yùn)行時(shí)錯(cuò)誤的可能性。它是現(xiàn)代Qt編程的推薦方式。
- Lambda表達(dá)式:非常靈活,適用于簡(jiǎn)單的、一次性的槽函數(shù)邏輯。但是,如果Lambda表達(dá)式過(guò)于復(fù)雜,可能會(huì)降低代碼的可讀性。
4.使用QOverload選擇重載信號(hào)的寫(xiě)法(Qt5.7)
使用QOverload選擇重載信號(hào)的寫(xiě)法同樣是在Qt5引入的,在Qt框架中具有顯著的優(yōu)點(diǎn),并且適用于特定的場(chǎng)景。例如使用comboBox時(shí),有時(shí)使用索引,有時(shí)使用字符串作為參數(shù):
QComboBox *comboBox = new QComboBox;
QLabel *label = new QLabel;
label->setText("初始文本");
// 添加一些選項(xiàng)到組合框
comboBox->addItem("選項(xiàng) 1");
comboBox->addItem("選項(xiàng) 2");
comboBox->addItem("選項(xiàng) 3");
// 使用 QOverload 來(lái)連接重載的信號(hào)到不同的槽
QObject::connect(comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
[](int index){ qDebug() << "當(dāng)前索引改變:" << index; });
QObject::connect(comboBox, QOverload<const QString&>::of(&QComboBox::currentIndexChanged),
[](const QString &text){ qDebug() << "當(dāng)前文本改變:" << text; });在這個(gè)例子中,currentIndexChanged信號(hào)被重載了兩次:一次接受一個(gè)整型參數(shù)(表示當(dāng)前選中項(xiàng)的索引),另一次接受一個(gè)字符串參數(shù)(表示當(dāng)前選中項(xiàng)的文本)。我們使用QOverload模板類來(lái)指定我們想要連接的是哪一個(gè)重載版本的信號(hào)。然后,我們使用lambda表達(dá)式來(lái)定義當(dāng)信號(hào)發(fā)出時(shí)執(zhí)行的代碼。QOverload是Qt 5.7及更高版本中引入的一個(gè)模板類,它用于在連接重載信號(hào)時(shí)提供類型安全。在Qt 5.7之前的版本中,您可能需要使用static_cast或函數(shù)指針來(lái)實(shí)現(xiàn)相同的功能,但這樣做通常不太安全且容易出錯(cuò)。
具體優(yōu)點(diǎn):
- 類型安全:
- 使用
QOverload可以確保在連接信號(hào)和槽時(shí),信號(hào)和槽的參數(shù)類型完全匹配。這有助于在編譯時(shí)捕獲潛在的錯(cuò)誤,提高代碼的穩(wěn)定性。
- 使用
- 清晰明確:
- 通過(guò)顯式地指定要連接的重載信號(hào)版本,代碼更加清晰易懂。其他開(kāi)發(fā)者可以一目了然地看到信號(hào)和槽之間的對(duì)應(yīng)關(guān)系,減少誤解和錯(cuò)誤。
- 靈活性:
QOverload允許開(kāi)發(fā)者在信號(hào)存在多個(gè)重載版本的情況下,選擇最適合當(dāng)前需求的信號(hào)版本進(jìn)行連接。這增加了代碼的靈活性,使其能夠適應(yīng)不同的場(chǎng)景和需求。
- 避免歧義:
- 在沒(méi)有
QOverload之前,如果信號(hào)存在多個(gè)重載版本,開(kāi)發(fā)者需要通過(guò)其他方式(如函數(shù)指針轉(zhuǎn)換)來(lái)指定要連接的信號(hào)版本,這可能會(huì)引入歧義和錯(cuò)誤。而QOverload提供了一種直接且明確的方式來(lái)避免這些問(wèn)題。
- 在沒(méi)有
這種寫(xiě)法用于當(dāng)信號(hào)存在多個(gè)重載版本時(shí),通過(guò)QOverload模板類明確指定要連接的是哪一個(gè)重載版本的信號(hào)。比如comboBox::currentIndexChanged信號(hào)可能有多個(gè)重載版本,而通過(guò)使用QOverload<int>或QOverload<const QString&>明確指定,然后進(jìn)行處理。適應(yīng)場(chǎng)景:
- 信號(hào)存在多個(gè)重載版本:
- 當(dāng)類中的信號(hào)存在多個(gè)重載版本時(shí),使用
QOverload可以明確指定要連接的重載信號(hào)版本,從而避免連接錯(cuò)誤或歧義。
- 當(dāng)類中的信號(hào)存在多個(gè)重載版本時(shí),使用
- 需要類型安全的信號(hào)槽連接:
- 在對(duì)類型安全要求較高的項(xiàng)目中,使用
QOverload可以確保信號(hào)和槽的參數(shù)類型完全匹配,減少運(yùn)行時(shí)錯(cuò)誤的可能性。
- 在對(duì)類型安全要求較高的項(xiàng)目中,使用
- 復(fù)雜的GUI應(yīng)用程序:
- 在復(fù)雜的GUI應(yīng)用程序中,信號(hào)和槽的連接可能變得非常復(fù)雜。使用
QOverload可以使代碼更加清晰易懂,方便維護(hù)和管理。
- 在復(fù)雜的GUI應(yīng)用程序中,信號(hào)和槽的連接可能變得非常復(fù)雜。使用
- 需要靈活處理不同參數(shù)類型的場(chǎng)景:
- 在某些場(chǎng)景下,可能需要根據(jù)不同的參數(shù)類型來(lái)處理信號(hào)。使用
QOverload可以方便地選擇不同參數(shù)類型的信號(hào)版本進(jìn)行連接,從而滿足這些需求。
- 在某些場(chǎng)景下,可能需要根據(jù)不同的參數(shù)類型來(lái)處理信號(hào)。使用
寫(xiě)到這里,感覺(jué)有點(diǎn)與孔乙己說(shuō)的茴字的幾種寫(xiě)法行為相仿,這里Qt里的connect函數(shù),簡(jiǎn)直就是編程界的“茴”字啊!孔乙己要是穿越到編程世界,看到connect的種種寫(xiě)法,怕是要笑得胡子都抖掉了,心里還得嘀咕:“這信號(hào)槽的connect,怎地也有如此多般變化,真是絕了!”
想象一下,咱們這connect函數(shù),簡(jiǎn)直就是編程里的“百搭小能手”,既能跟老式的函數(shù)指針眉來(lái)眼去,又能跟新潮的Lambda表達(dá)式暗送秋波,還能跟那信號(hào)映射機(jī)制搞點(diǎn)小曖昧。這不,就像孔乙己研究“茴”字的幾種寫(xiě)法一樣,咱們程序員也得琢磨琢磨connect的幾種姿勢(shì)-_-||b
在選擇哪種寫(xiě)法時(shí),應(yīng)根據(jù)具體的需求和代碼風(fēng)格來(lái)決定。對(duì)于復(fù)雜的槽函數(shù)邏輯,傳統(tǒng)的槽函數(shù)可能更合適;對(duì)于簡(jiǎn)單的邏輯或臨時(shí)的連接,Lambda表達(dá)式可能更方便;而函數(shù)指針的connect則通常是一個(gè)折中的選擇,既安全又易于使用。
總結(jié)
到此這篇關(guān)于關(guān)于Qt C++中connect的幾種寫(xiě)法的文章就介紹到這了,更多相關(guān)Qt C++中connect寫(xiě)法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++常用函數(shù)總結(jié)(algorithm 頭文件)
本文給大家詳細(xì)介紹了algorithm 頭文件中最常用的函數(shù)及其使用方法,當(dāng)然這只是其中的一部分,algorithm 頭文件中還有很多其他的函數(shù),感興趣的朋友一起看看吧2023-12-12
一起來(lái)學(xué)習(xí)C++中類的this指針以使用
這篇文章主要為大家詳細(xì)介紹了C++中類的this指針以使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
C語(yǔ)言深入探究sizeof與整型數(shù)據(jù)存儲(chǔ)及數(shù)據(jù)類型取值范圍
在main函數(shù)中,sizeof是可以正常工作的,但是在自定義函數(shù)中就不可以了。所以本文將為大家詳細(xì)講解一下關(guān)鍵字sizeof、整型數(shù)據(jù)存儲(chǔ)深入、數(shù)據(jù)類型取值范圍深入2022-07-07
淺談關(guān)于指針作為參數(shù)并改變它的值的問(wèn)題
這篇文章介紹了關(guān)于指針作為參數(shù)并改變它的值的問(wèn)題,有需要的朋友可以參考一下2013-10-10
C語(yǔ)言實(shí)現(xiàn)隨機(jī)抽獎(jiǎng)程序
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)隨機(jī)抽獎(jiǎng)程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09

