Qt - 信号与槽

1. 信号与槽概述

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式(发布-订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

1.1 信号的本质

信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候Qt对应的窗口类会发出某个信号,以此对用户的挑选做出反应。

因此根据上述的描述我们得到一个结论:信号的本质就是事件,比如:

  • 按钮单击、双击

  • 窗口刷新

  • 鼠标移动、鼠标按下、鼠标释放

  • 键盘输入

那么在Qt中信号是通过什么形式呈现给使用者的呢?

  • 我们对哪个窗口进行操作, 哪个窗口就可以捕捉到这些被触发的事件。

  • 对于使用者来说触发了一个事件我们就可以得到Qt框架给我们发出的某个特定信号。

  • 信号的呈现形式就是函数, 也就是说某个事件产生了, Qt框架就会调用某个对应的信号函数, 通知使用者。

在QT中信号的发出者是某个实例化的类对象,对象内部可以进行相关事件的检测。

1.2 槽的本质

槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的C++函数是一样的,可以定义在类的任何部分(public、private或 protected),可以具有任何参数,可以被重载,也可以被直接调用(但是不能有默认参数)。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

举个简单的例子:

女朋友说:“我肚子饿了!”,于是我带她去吃饭。

上边例子中相当于女朋友发出了一个信号, 我收到了信号并其将其处理掉了。

  • 女朋友 -> 发送信号的对象, 信号内容: 我饿了

  • 我 -> 接收信号的对象并且处理掉了这个信号, 处理动作: 带她去吃饭

在Qt中槽函数的所有者也是某个类的实例对象。

写信:发件人 信的内容 收件人 收到信做事情

 

1.3 信号与槽的关系

在Qt中信号和槽函数都是独立的个体,本身没有任何联系,但是由于某种特性需求我们可以将二者连接到一起,好比牛郎和织女想要相会必须要有喜鹊为他们搭桥一样。

信号与槽关联是用 QObject::connect() 函数实现的,其函数原型是:

[static] QMetaObject::Connection  QObject::connect(
    const QObject *sender,                              
    const char *signal,                                 
    const QObject *receiver,                            
    const char *method,                                 
    Qt::ConnectionType type = Qt::AutoConnection);
  • 参数:

    • sender: 发出信号的对象

    • signal: sender对象的信号,信号是一个函数

    • receiver: 信号接收者

    • method: receiver对象的槽函数, 当检测到sender发出了signal信号, receiver对象调用method方法

connect函数相对于做了信号处理动作的注册,调用conenct连接信号与槽时,sender对象的信号并没有产生, 因此receiver对象的method也不会被调用,method槽函数本质是一个回调函数, 调用的时机是信号产生之后。 调用槽函数是Qt框架来执行的,connect中的sender和recever两个指针必须被实例化了, 否则conenct不会成功

2. 标准信号与槽

在Qt提供的很多类中都可以对用户触发的某些特定事件进行检测, 当事件被触发后就会产生对应的信号, 这些信号都是Qt类内部自带的, 因此称之为标准信号。

同样的,在Qt的很多类内部为我了提供了很多功能函数,并且这些函数也可以作为触发的信号的处理动作,有这类特性的函数在Qt中称之为标准槽函数。

系统自带的信号和槽通常如何查找呢,这个就需要利用帮助文档了,在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入QPushButton,首先我们可以在Contents中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该看当前类从父类继承下来了哪些信号,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个

 

2.1 信号与槽的使用

功能实现: 点击窗口上的按钮, 关闭窗口

  • 按钮: 信号发出者 -> QPushButton::clicked

  • 窗口: 信号接收者 -> QMainWindow::close

// 单击按钮发出的信号
[signal] void QAbstractButton::clicked(bool checked = false)
// 关闭窗口的槽函数
[slot] bool QWidget::close();

// 单击按钮关闭窗口(Qt5的连接方式)
connect(ui->closeBtn, &QPushButton::clicked, this, &MainWindow::close);

// 单击按钮关闭窗口(Qt4的连接方式)
connect(ui->closeBtn, SIGNAL( clicked() ), this, SLOT( close() ));

功能实现: 选择组合框项,打印出对应的下标

槽函数实现:

public slots:
    void onActivated(int index);

void MainWindow::onActivated(int index)
{
    qDebug()<<"index = "<<index;
}
//添加项
ui->comboBox->addItem("中文");
ui->comboBox->addItem("英语");
ui->comboBox->addItem("日语");

connect(ui->comboBox, SIGNAL(activated(int)), this, SLOT(onActivated(int)));

 

2.2 信号与槽连接方式

  • Qt5的连接方式

    // Qt5的connect()函数原型
    QMetaObject::Connection QObject::connect(
            const QObject *sender, PointerToMemberFunction signal, 
            const QObject *receiver, PointerToMemberFunction method, 
            Qt::ConnectionType type = Qt::AutoConnection);
    ​
    // 信号和槽函数也就是第2,4个参数传递的是地址, 编译器在编译过程中会对数据的正确性进行检测
    connect(const QObject *sender, &QObject::signal, const QObject *receiver, &QObject::method);

     

  • Qt4的连接方式

    这种旧的信号槽连接方式在Qt5中是支持的, 但是不推荐使用, 因为这种方式在进行信号槽连接的时候, 信号槽函数通过宏SIGNALSLOT转换为字符串类型。

    因为信号槽函数的转换是通过宏来进行转换的,因此传递到宏函数内部的数据不会被进行检测, 如果使用者传错了数据,编译器也不会报错,但实际上信号槽的连接已经不对了,只有在程序运行起来之后才能发现问题,而且问题不容易被定位。

    // Qt4的connect()函数原型
    [static] QMetaObject::Connection QObject::connect(
            const QObject *sender, const char *signal, 
            const QObject *receiver, const char *method, 
            Qt::ConnectionType type = Qt::AutoConnection);
    ​
    connect(const QObject *sender,SIGNAL(信号函数名(参数1, 参数2, ...)),const QObject *receiver,SLOT(槽函数名(参数1, 参数2, ...)));

 

2.3 重载信号和槽

  • 应用举例

    class Me : public QObject
    {
        Q_OBJECT
    
    signals:
        void hungury();
        void hungury(QString somthing);
    
    public slots:
        void eat()
        {
            qDebug()<<"不参数的信号与槽";
        }
        void eat(QString somthing)
        {
            qDebug()<<"带参数的信号与槽:"<<somthing;
        }
    };

基于上面写的信号与槽,我们来处理如下逻辑: 我饿了, 我要吃东西

  • 分析: 信号的发出者是我自己, 信号的接收者也是我自己

        // Qt4处理方式  注意不要把信号与槽的名字写错了,因为是转为字符串写错了不会报错,但是连接会失败
        connect(&me, SIGNAL(eat()), &me, SLOT(hungury()));
        connect(&me, SIGNAL(eat(QString)), &me, SLOT(hungury(QString)));
    
        // Qt5处理方式  会报错,报“没有匹配调用connect的成员函数”
        connect(&me, &Me::eat, &me, &Me::hungury);    // error:no matching member function for call to 'connect'
  • 为什么Qt4的方式没有错误,Qt5的方式却有问题了呢?

    • Qt4的方式在传信号和槽的时候用了宏进行强转,而且都带了参数,不会有二义性问题产生

    • Qt5中,信号和槽都有重载,此事connect函数根本就不知道你要使用的是重载中的哪一个,所以只能报错咯!

  • 如何解决Qt5中的信号和槽重载中的二义性问题呢?

    • 方法一:通过函数指针解决

      //定义信号的函数指针
      void (Me::*funcHungury)() = &Me::hungury;
      void (Me::*funcHungury_QString)(QString) = &Me::hungury;
      //定义槽的函数指针
      void (Me::*funcEat)() = &Me::eat;
      void (Me::*funcEat_QString)(QString) = &Me::eat;
      
      //无参连接
      connect(this, funcHungury, this, funcEat);
      //有参连接
      connect(this, funcHungury_QString, this, funcEat_QString);
    • 方法二:通过Qt提供的重载类(QOverload)解决

      //有参连接
      connect(this, QOverload<QString>::of(&Me::hungury), this, QOverload<QString>::of(&Me::eat));
      //无参连接
      connect(this, QOverload<>::of(&Me::hungury), this, QOverload<>::of(&Me::eat));
  • 总结

    • Qt4的信号槽连接方式因为使用了宏函数, 宏函数对用户传递的信号槽不会做错误检测, 容易出bug

    • Qt5的信号槽连接方式, 传递的是信号槽函数的地址, 编译器会做错误检测, 减少了bug的产生

    • 当信号槽函数被重载之后, Qt4的信号槽连接方式不受影响

    • 当信号槽函数被重载之后, Qt5中需要给被重载的信号或者槽定义函数指针

所有代码:

查看代码
#include <QObject>
#include <QDebug>


class Me : public QObject
{
    Q_OBJECT

signals:
    void hungury();
    void hungury(QString somthing);

public slots:
    void eat()
    {
        qDebug()<<"不参数的信号与槽";
    }
    void eat(QString somthing)
    {
        qDebug()<<"带参数的信号与槽:"<<somthing;
    }

public:
    Me()
    {
        if (0)//方法一:通过函数指针解决
        {
            //定义信号的函数指针
            void (Me::*funcHungury)() = &Me::hungury;
            void (Me::*funcHungury_QString)(QString) = &Me::hungury;
            //定义槽的函数指针
            void (Me::*funcEat)() = &Me::eat;
            void (Me::*funcEat_QString)(QString) = &Me::eat;

            //无参连接
            connect(this, funcHungury, this, funcEat);
            //有参连接
            connect(this, funcHungury_QString, this, funcEat_QString);

            //发无参数的信号
            this->hungury();
            //发带参数的信号
            this->hungury("炸鸡");
        }
        else//方法二:通过Qt提供的重载类(QOverload)解决
        {
            //有参连接
            connect(this, QOverload<QString>::of(&Me::hungury), this, QOverload<QString>::of(&Me::eat));
            //无参连接
            connect(this, QOverload<>::of(&Me::hungury), this, QOverload<>::of(&Me::eat));

            //发无参数的信号
            this->hungury();
            //发带参数的信号
            this->hungury("炸鸡");
        }
    }
};


void test()
{
    Me me;

    //定义信号的函数指针
    void (Me::*funcHungury)() = &Me::hungury;
    void (Me::*funcHungury_QString)(QString) = &Me::hungury;
    //定义槽的函数指针
    void (Me::*funcEat)() = &Me::eat;
    void (Me::*funcEat_QString)(QString) = &Me::eat;

    //无参连接
    QObject::connect(&me, funcHungury, &me, funcEat);
    //有参连接
    QObject::connect(&me, funcHungury_QString, &me, funcEat_QString);

    //发无参数的信号
    me.hungury();
    //发带参数的信号
    me.hungury("炸鸡");
}



int main()
{
    //test();
    Me me;

    return 0;
}

 

3. 自定义信号与槽

Qt框架提供的信号槽在某些特定场景下是无法满足我们的项目需求的,因此我们还设计自己需要的的信号和槽,同样还是使用connect()对自定义的信号槽进行连接。

如果想要使用自定义的信号和槽, 首先要编写新的类并且让其继承Qt的某些标准类,我们自己编写的类想要在Qt中使用使用信号槽机制, 那么必须要满足的如下条件:

  • 这个类必须从QObject类或者是其子类进行派生

  • 在定义类的第一行头文件中加入 Q_OBJECT 宏

// 在头文件派生类的时候,首先像下面那样引入Q_OBJECT宏:
class MyMainWindow : public QWidget
{
    Q_OBJECT
public:
    ......
}

 

3.1 自定义信号

注意点:

  • 信号是类的成员函数

  • 返回值是 void 类型

  • 参数可以随意指定, 信号也支持重载

  • 信号需要使用 signals 关键字进行声明, 使用方法类似于public等关键字

  • 信号函数只需要声明, 不需要定义(没有函数体实现)

  • 在程序中发送自定义信号:发送信号的本质就是调用信号函数

定义信号:

// 举例: 信号重载
// Qt中的类想要使用信号槽机制必须要从QObject类派生(直接或间接派生都可以)
class GirlFriend: public QObject
{
    Q_OBJECT
    
public:
    GirlFriend(QObject*parent = nullptr):QObject(parent){}
    
signals:
    void hungry();
    void hungry2(QString str);
};

信号参数的作用是数据传递, 谁调用信号函数谁就指定实参,实参最终会被传递给槽函数

发送信号:

emit mysignals();   //发送信号

emit是一个空宏,没有特殊含义,仅用来表示这个语句是发射一个信号,不写当然可以,但是不推荐。

 

3.2 自定义槽

槽函数就是信号的处理动作,自定义槽函数和自定义的普通函数写法是一样的。

特点:

  • 返回值是 void 类型

  • 槽函数也支持重载

    • 槽函数参数个数, 需要看连接的信号的参数个数

    • 槽函数的参数是用来接收信号发送的数据的, 信号的参数就是需要发送的数据

    • 举例:

      • 信号函数: void testsig(int a, double b);

      • 槽函数: void testslot(int a, double b);

    • 总结:

      • 槽函数的参数应该和对应的信号的参数个数, 类型一一对应

      • 信号的参数可以大于等于槽函数的参数个数,未被槽函数接受的数据会被忽略

        • 信号函数: void testsig(int a, double b);

        • 槽函数: void testslot(int a);

槽函数的类型:

  • 成员函数

    • 普通成员函数

    • 静态成员函数

  • 全局函数

  • lambda表达式(匿名函数)

  1. 槽函数可以使用关键字进行声明: slots (Qt5中slots可以省略不写)

    • public slots:

    • private slots:

    • protected slots:

场景举例

女朋友饿了, 我请她吃饭
class GirlFriend
class OneSelf

GirlFriend.h

#ifndef GIRLFRIEND_H
#define GIRLFRIEND_H

#include <QObject>
#include <QDebug>

class GirlFriend:public QObject
{
    Q_OBJECT
public:
    GirlFriend(QObject*parent = nullptr):QObject(parent){}
signals:
    void hungry();
    void hungry2(QString str);
};


class OneSelf:public QObject
{
    Q_OBJECT
public:
    OneSelf(QObject*parent = nullptr):QObject(parent){}
    void goEat()
    {
        qDebug()<<"goEat";
    }
    static void goEatFood()
    {
        qDebug()<<"goEatFood";
    }
public slots:
    void onHungry()
    {
        qDebug()<<"宝贝饿了呀,多喝热水哟~";
    }
    void onHungry2(QString str)
    {
        qDebug()<<"宝贝饿了呀,吃-》"<<str;
    }
};

#endif // GIRLFRIEND_H
  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class GirlFriend;
class OneSelf;

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

public slots:
    void onBtnClicked();

private:
    Ui::Widget *ui;

    GirlFriend* girl;
    OneSelf* self;
};
#endif // WIDGET_H
  • widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QPushButton>
#include "GirlFriend.h"

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    //创建对象
    girl = new GirlFriend(this);
    self = new OneSelf(this);

    //连接槽函数,不带参数
    connect(girl, &GirlFriend::hungry, self, &OneSelf::onHungry);
    //连接槽函数,带参数
    connect(girl, &GirlFriend::hungry2, self, &OneSelf::onHungry2);
    //连接普通成员函数
    //connect(girl, &GirlFriend::hungry, self, &OneSelf::goEat);
    //连接静态成员函数
    //connect(girl, &GirlFriend::hungry, self, &OneSelf::goEatFood);

    //创建负责发送信号的按钮
    QPushButton* btn = new QPushButton("按下就饿了",this);
    //通过widget间接发送girl的hungry信号
    connect(btn, &QPushButton::clicked, this, &Widget::onBtnClicked);
    //连接信号,直接发送girl的hungry信号,信号连接信号
    //connect(btn, &QPushButton::clicked, girl, &GirlFriend::hungry);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::onBtnClicked()
{
    emit girl->hungry();
    emit girl->hungry2("汉堡");
}

运行结果:

 

4. 信号与槽拓展

4.1 一个信号对应多个槽

  • 一个信号对应多个槽时,槽函数的执行顺序怎样的?

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void on_pushButton_clicked();
    void myslot1(QString); //定义私有槽
    void myslot2(QString); //定义私有槽
    void myslot3(QString); //定义私有槽
private:
    Ui::MainWindow *ui;
};

//公有继承自 QObject
class MyClass : public QObject
{
    Q_OBJECT //声明宏,为了可以使用信号槽机制
public:
    MyClass(){}
    ~MyClass(){}
signals:
    void mysignal(QString); //定义信号(信号全部是公有的)
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MyClass myclass; //MyClass实例化

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //信号槽连接(连接顺序:slot2, slot1, slot3)
    connect(&myclass,SIGNAL(mysignal(QString)), this,SLOT(myslot2(QString)),Qt::UniqueConnection);
    connect(&myclass,SIGNAL(mysignal(QString)), this,SLOT(myslot1(QString)),Qt::UniqueConnection);
    connect(&myclass,SIGNAL(mysignal(QString)), this,SLOT(myslot3(QString)),Qt::UniqueConnection);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    //触发信号(推荐在本类触发信号,这里只是为了演示目的)
    emit myclass.mysignal("这是一条来自myclass对象的信号");
}

//槽的实现
void MainWindow::myslot1(QString str)
{
    qDebug()<<"slot1:"<<str;
}
void MainWindow::myslot2(QString str)
{
    qDebug()<<"slot2:"<<str;
}
void MainWindow::myslot3(QString str)
{
    qDebug()<<"slot3:"<<str;
}

运行结果如下:

得出结论: 槽函数的执行顺序和信号槽连接的顺序一致

 

4.2 多个信号对应一个槽

  • 多个信号对应一个槽时,如何在槽函数中判断发出者?

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void on_pushButton_clicked();
    void myslot(QString); //定义私有槽
private:
    Ui::MainWindow *ui;
};

//公有继承自 QObject
class MyClass : public QObject
{
    Q_OBJECT //声明宏,为了可以使用信号槽机制
public:
    MyClass(){}
    ~MyClass(){}
signals:
    void mysignal(QString); //定义信号(信号全部是公有的)
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MyClass myclass1; //MyClass实例化1
MyClass myclass2; //MyClass实例化2
MyClass myclass3; //MyClass实例化3

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    myclass1.setObjectName("myclass1");
    myclass2.setObjectName("myclass2");
    myclass3.setObjectName("myclass3");
    //信号槽连接
    connect(&myclass1,SIGNAL(mysignal(QString)), this,SLOT(myslot(QString)),Qt::UniqueConnection);
    connect(&myclass2,SIGNAL(mysignal(QString)), this,SLOT(myslot(QString)),Qt::UniqueConnection);
    connect(&myclass3,SIGNAL(mysignal(QString)), this,SLOT(myslot(QString)),Qt::UniqueConnection);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    //触发信号(推荐在本类触发信号,这里只是为了演示目的)
    emit myclass1.mysignal("这是一条测试信号");
    emit myclass2.mysignal("这是一条测试信号");
    emit myclass3.mysignal("这是一条测试信号");
}

//槽的实现
void MainWindow::myslot(QString str)
{
    qDebug()<<"from "<<sender()->objectName()<<""<<str;
}

运行结果如下:

 

原理:首先利用 QObject::setObjectName(const QString&) 方法设置信号发出者的对象名称,

然后在槽函数中利用 QObject::sender()->objectName() 方法获取信号发出者的对象名称。

 

4.3 信号连接信号

  • 信号接收者可以不出来接收的信号, 继续发出新的信号 -> 传递了数据, 并没有进行处理
void MainWindow::onClicked()
{
    qDebug()<<"btn2 onClicked";
}

void MainWindow::test2()
{
    QPushButton*btn = new QPushButton("btn",this);
    QPushButton*btn2 = new QPushButton("btn2",this);
    btn2->move(100,0);

    connect(btn, &QPushButton::clicked, btn2, &QPushButton::clicked);//点击btn按钮,会让btn2按钮发出clicked信号 ​
    connect(btn2, &QPushButton::clicked, this, &MainWindow::onClicked);//点击btn2按钮,会执行onClicked()槽函数 ​
}

 

4.4 断开信号与槽

  • 断开信号与槽使用disconnect()函数

函数原型:

disconnect(const QObject *sender,
           &QObject::signal, 
           const QObject *receiver, 
           &QObject::method);

示例代码:

disconnect(btn, &QPushButton::clicked, this, &MainWindow::onClicked);

disconnect(btn, SIGNAL( clicked() ), this, SLOT( onClicked() ));

4.5 Lambda表达式

  • Lambda表达式是C++11最重要也是最常用的特性之一,是现代编程语言的一个特点,简洁,提高了代码的效率并且可以使程序更加灵活,Qt是完全支持c++语法的, 因此在Qt中也可以使用Lambda表达式。

Lambda表达式就是一个匿名函数, 语法格式如下:

[capture](params) opt -> ret {body;};
      - capture: 捕获列表
    - params: 参数列表
    - opt: 函数选项
    - ret: 返回值类型
    - body: 函数体
        
// 示例代码->匿名函数的调用:
int ret = [](int a) -> int
{
    return a+1;
}(100);

 

示例:

QPushButton*btn = new QPushButton("touch me",this);
QPushButton*btn2 = new QPushButton("青青子衿",this);
btn2->move(100,0);
​
//禁止用&引用捕获临时变量,因为函数结束变量会销毁,在lambda中使用会产生错误
//应该使用按值捕获 = 
connect(btn,&QPushButton::clicked,this,[=]()
{
    static  int flag = false;   //可以这样用
    if(!flag)
    {
        btn2->setText("悠悠我心");
    }else
    {
        btn2->setText("但为君故");
    }
    flag = !flag;
});

 

关于Lambda表达式的细节介绍:

  1. 捕获列表: 捕获一定范围内的变量

    • []- 不捕捉任何变量

    • [&]- 捕获外部作用域中所有变量, 并作为引用在函数体内使用 (按引用捕获)

    • [=]- 捕获外部作用域中所有变量, 并作为副本在函数体内使用 (按值捕获)

      • 拷贝的副本在匿名函数体内部是只读的

    • [=, &foo] - 按值捕获外部作用域中所有变量, 并按照引用捕获外部变量 foo

    • [bar] - 按值捕获 bar 变量, 同时不捕获其他变量

    • [&bar] - 按值捕获 bar 变量, 同时不捕获其他变量

    • [this] - 捕获当前类中的this指针

      • 让lambda表达式拥有和当前类成员函数同样的访问权限

      • 如果已经使用了 & 或者 =, 默认添加此选项

  2. 参数列表: 和普通函数的参数列表一样

  3. opt 选项 --> 可以省略

    • mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)

    • exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用throw();

  4. 返回值类型:

    • 标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略

  5. 函数体:

    • 函数的实现,这部分不能省略,但函数体可以为空。

posted @ 2022-04-15 10:48  [BORUTO]  阅读(224)  评论(0编辑  收藏  举报