QT之靜態函式傳送訊號

澆築菜鳥發表於2021-09-13

一、簡介

由於博主本人是初學者對QT的機制不瞭解,所以遇到了一個比較大的坑,特此記錄一下。我遇到的問題是無法在靜態函式中向另外一個類傳送訊號。解決辦法:先將訊號傳送給同類中的普通函式,然後在從普通函式中傳送訊號給外部類。

二、C與C++中static的用法

這裡不是介紹QT靜態函式訊號的傳送嗎,和static的用法有什麼聯絡,因為在編寫程式碼中會出現靜態成員無法訪問普通成員的錯誤,這裡我複製了菜鳥教程的圖片。

接下來先了解一下static的用法。

  1. C語言中static的作用
    主要有三個作用:隱藏性、永續性、預設值為0
  • 隱藏性:當我們同時編譯多個檔案時,所有未加 static 字首的全域性變數和函式都具有全域性可見性。
  • 永續性:在函式內部使用static修飾變數時,不僅可以是變數具有隱藏性,還能增加變數生命。
  • 預設初始化為 0:在靜態資料區,記憶體中所有的位元組預設值都是 0x00,其實全域性變數也具備這一屬性,因為全域性變數也儲存在靜態資料區。
    想了解具體的用法可以去菜鳥教程學習《C 語言中 static 的作用》。
  1. 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

相關文章