一、簡介
由於博主本人是初學者對QT的機制不瞭解,所以遇到了一個比較大的坑,特此記錄一下。我遇到的問題是無法在靜態函式中向另外一個類傳送訊號。解決辦法:先將訊號傳送給同類中的普通函式,然後在從普通函式中傳送訊號給外部類。
二、C與C++中static的用法
這裡不是介紹QT靜態函式訊號的傳送嗎,和static的用法有什麼聯絡,因為在編寫程式碼中會出現靜態成員無法訪問普通成員的錯誤,這裡我複製了菜鳥教程的圖片。
接下來先了解一下static的用法。
- C語言中static的作用
主要有三個作用:隱藏性、永續性、預設值為0
- 隱藏性:當我們同時編譯多個檔案時,所有未加 static 字首的全域性變數和函式都具有全域性可見性。
- 永續性:在函式內部使用static修飾變數時,不僅可以是變數具有隱藏性,還能增加變數生命。
- 預設初始化為 0:在靜態資料區,記憶體中所有的位元組預設值都是 0x00,其實全域性變數也具備這一屬性,因為全域性變數也儲存在靜態資料區。
想了解具體的用法可以去菜鳥教程學習《C 語言中 static 的作用》。
- C++ 中static的作用
C++中使用static需要主要的地方
- 靜態成員函式中不能呼叫非靜態成員。
- 非靜態成員函式中可以呼叫靜態成員。因為靜態成員屬於類本身,在類的物件產生之前就已經存在了,所以在非靜態成員函式中是可以呼叫靜態成員的。
- 靜態成員變數使用前必須先初始化(如 int MyClass::m_nNumber = 0;),否則會在 linker 時出錯。
修飾成員變數
- 靜態資料成員可以實現多個物件之間的資料共享,它是類的所有物件的共享成員,它在記憶體中只佔一份空間,如果改變它的值,則各物件中這個資料成員的值都被改變。
- 靜態資料成員是在程式開始執行時被分配空間,到程式結束之後才釋放,只要類中指定了靜態資料成員,即使不定義物件,也會為靜態資料成員分配空間。
- 靜態資料成員可以被初始化,但是隻能在類體外進行初始化,若未對靜態資料成員賦初值,則編譯器會自動為其初始化為 0。
- 靜態資料成員既可以通過物件名引用,也可以通過類名引用。
修飾成員函式
- 靜態成員函式和靜態資料成員一樣,他們都屬於類的靜態成員,而不是物件成員。
- 非靜態成員函式有 this 指標,而靜態成員函式沒有 this 指標。
- 靜態成員函式主要用來方位靜態資料成員而不能訪問非靜態成員。
想了解具體的用法可以去菜鳥教程學習《C/C++ 中 static 的用法全域性變數與區域性變數》。
三、程式原始碼
ClassA.h 檔案
#ifndef CLASSA_H
#define CLASSA_H
#include <QObject>
#include <iostream>
class ClassA : public QObject
{
Q_OBJECT
public:
ClassA();
~ClassA();
static void SignalGeneration(); //靜態函式,訊號將從此函式發生
private:
static ClassA *myClassA; //它在記憶體中只佔一份空間
signals:
void SigExternal(QString str); //向外部的類傳送訊號
void SigInsideDelier(char *str); //傳送訊號到此類的訊號槽
private slots:
void SlotInsideDelier(char *str); //內部槽 用於響應內部訊號
};
#endif // CLASSA_H
ClassA.cpp檔案
#include "ClassA.h"
ClassA *ClassA::myClassA = NULL; // 靜態成員變數使用前必須先初始化,否則使用是會提示變數未定義
ClassA::ClassA()
{
myClassA = this;
connect(this, &ClassA::SigInsideDelier, [this](char *str)
{
emit SlotInsideDelier(str);
});
}
void ClassA::SignalGeneration()
{
const char *str = "訊號生產成功";
emit myClassA->SigInsideDelier((char *)str);
}
void ClassA::SlotInsideDelier(char *str)
{
emit SigExternal(QString(str));
}
ClassA::~ClassA()
{
}
widget.h檔案
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "ClassA.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
void classA_msg(QString str);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp檔案
#include "widget.h"
#include "ui_widget.h"
#include <iostream>
#include "ClassA.h"
using namespace std;
ClassA *classA;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
classA = new ClassA();
connect(classA, SIGNAL(SigExternal(QString)), this, SLOT(classA_msg(QString))); //注意這裡傳遞訊號必須使用QString不能使用char *,否則接收資料會異常,具體原因未知
ui->setupUi(this);
}
Widget::~Widget()
{
delete classA;
delete ui;
}
void Widget::on_pushButton_clicked()
{
ClassA::SignalGeneration();
}
void Widget::classA_msg(QString str)
{
ui->plainTextEdit->appendPlainText(str);
}
程式介面
四、執行測試
參考文獻
C 語言中 static 的作用:https://www.runoob.com/w3cnote/c-static-effect.html
C/C++ 中 static 的用法全域性變數與區域性變數:https://www.runoob.com/w3cnote/cpp-static-usage.html
Qt知識點梳理 —— 靜態函式傳送訊號:https://blog.csdn.net/tingzhiyi/article/details/112631489