一 函數指針:
顧名思義,函數指針即指向函數之指針,它與其他普通類型指針一樣,所佔內存爲4個字節(32位系統)。所不同的是其內部存儲了函數的地址而非數據地址,函數指針可以實現對參數類型、參數順序、返回值都相同的函數進行封裝,是多態的一種實現方式。
其一般的使用非常簡單,假如返回值爲int類型,入參有兩個從左到右分別爲char*和int,那麼聲明此類函數指針如下:
int (*pFunc)(char*, int);
假設有如下形式的函數:
int Test(char *pSz, int nCount);
那麼函數指針的使用如下:
pFunc = Test;
// 亦可
pFunc = &Test;
說個更有趣的使用(祕密武器, 一般人不告訴他...):
//! 都可以
pFunc = *Test;
PFunc = **Test;
pFunc = ***Test;
//...
實際使用一般會用typedef定義爲一種類型:
typedef int (*PFUNC)(char*, int);
使用時,需先要聲明對象:
PFUNC pFunc = Test;
二 類函數指針:
類的靜態成員函數採用與一般函數指針相同的調用方式,不受this指針的影響;類的非靜態成員函數與一般函數指針是不兼容的。而且,不同類的this指針是不一樣的,因此,指向不同類的非靜態成員函數的指針也是不兼容的。指向類的非靜態成員函數的指針,在聲明時就需要添加類名。
類函數指針之靜態成員函數:
//! 指向一般類的靜態成員函數的指針定義
typedef int (*pGeneralFun)(int, int);
類函數指針之非靜態成員函數:
//! 指向類的非靜態成員函數的指針定義
typedef int (CA::*pClassFun)(int, int);
三 類函數指針在Qt信號槽的使用:
有如下程序(照搬之):
//!!! Qt5
#include <QObject>
////////// newspaper.h
class Newspaper : public QObject
{
Q_OBJECT
public:
Newspaper(const QString & name) :
m_name(name)
{
}
void send() const
{
emit newPaper(m_name);
}
signals:
void newPaper(const QString &name) const;
private:
QString m_name;
};
////////// reader.h
#include <QObject>
#include <QDebug>
class Reader : public QObject
{
Q_OBJECT
public:
Reader() {}
void receiveNewspaper(const QString & name) const
{
qDebug() << "Receives Newspaper: " << name;
}
};
////////// main.cpp
#include <QCoreApplication>
#include "newspaper.h"
#include "reader.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Newspaper newspaper("Newspaper A");
Reader reader;
QObject::connect(&newspaper, &Newspaper::newPaper,
&reader, &Reader::receiveNewspaper);
newspaper.send();
return app.exec();
}
上面connect()函數可以正常綁定信號槽,但是信號如同普通成員函數一樣也支持重載,添加如下信號:
void newPaper(const QString &name, const QDate &date);
按照前面的寫法,編譯器會報出一個錯誤:由於這個函數(注意,信號實際也是一個普通的函數)有重載,因此不能用一個取址操作符獲取其地址。在 Qt 4 中,我們使用SIGNAL和SLOT兩個宏來連接信號槽。如果有一個帶有兩個參數的信號,由於其信號槽的連接是帶參數的,所以connect()函數使用Qt4的風格編寫是沒有問題的,代碼如下:
QObject::connect(&newspaper, SIGNAL(newPaper(QString, QDate)),
&reader, SLOT(receiveNewspaper(QString, QDate)));
此種場景下,之前講述的類成員(非靜態)函數指針便派上用場了:
void (Newspaper:: *newPaperNameDate)(const QString &, const QDate &) = &Newspaper::newPaper;
QObject::connect(&newspaper, newPaperNameDate,
&reader, &Reader::receiveNewspaper);
根本原因是,我們指明瞭函數類型,使編譯器能夠準確定位。當然你也可以直接聲明(類型轉換):QObject::connect(&newspaper, (void (Newspaper:: *)(const QString &, const QDate &))&Newspaper::newPaper,
&reader, &Reader::receiveNewspaper);
本文簡要講述了函數指針及其在Qt的信號槽中的使用,部分代碼取自互聯網,感謝分享。還有一些其他細節就不在此展開了,請自行查閱,見諒!