在c++里,当设计一个底层类的时候,下游不知道上游具体的类是什么,又需要调上游的方法(比如通过通信获取到了数据,需要将数据回传到上游),解决方法是将上游类的成员函数(其他函数同理)充当回调函数,传递给下游。
上游类:mainwindow
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class ServerProvider;
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
void getData(const QString &str);
private:
Ui::MainWindow *ui;
ServerProvider *m_serverProvider;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <functional>
#include "serverprovider.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
FuncDef func;
func = std::bind(&MainWindow::getData, this, std::placeholders::_1);
m_serverProvider = new ServerProvider();
m_serverProvider->setFunc(func);
}
MainWindow::~MainWindow() { delete ui; }
void MainWindow::getData(const QString &str) {
qDebug() << "GET DATA: " << str;
}
下游类:serverprovider
#ifndef SERVERPROVIDER_H
#define SERVERPROVIDER_H
#include <functional>
class QString;
typedef std::function<void(const QString &str)> FuncDef;
class ServerProvider {
public:
ServerProvider();
void setFunc(FuncDef func);
private:
FuncDef m_func;
};
#endif // SERVERPROVIDER_H
#include "serverprovider.h"
#include <QString>
ServerProvider::ServerProvider() {}
void ServerProvider::setFunc(FuncDef func) {
this->m_func = func;
//假设此处获得数据
//(实际场景这个方法只做setFunc,应该是在某个触发条件下调用m_func)
QString str = "Hello World!";
this->m_func(str);
}
如何使用QT自带的反射机制,运行槽函数呢?(QT6.2.3里信号和槽使用回调函数的原理就是这样,其他的还有兼容老式的用法)
//test.h
class Test {
public:
Test();
~Test();
template <typename Func>
void slotFlex(const typename QtPrivate::FunctionPointer<Func>::Object *sender,
Func slot) {
typedef QtPrivate::FunctionPointer<Func> SlotType;
m_slotObject = new QtPrivate::QSlotObject<
Func,
typename QtPrivate::List_Left<typename SlotType::Arguments,
SlotType::ArgumentCount>::Value,
typename SlotType::ReturnType>(slot);
m_object = const_cast<QObject *>(dynamic_cast<const QObject *>(sender));
}
void test();
private:
QtPrivate::QSlotObjectBase *m_slotObject;
QObject *m_object;
};
//test.cpp
#include "test.h"
Test::Test() {}
Test::~Test() {
if (m_slotObject != nullptr) {
m_slotObject->destroyIfLastRef();
}
}
void Test::test() {
int a = 10;
void *argv[] = {
nullptr,
const_cast<void *>(reinterpret_cast<const void *>(std::addressof(a))),
};
m_slotObject->call(m_object, argv);
}
使用:
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class Test;
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void testSlots(int a);
private:
Ui::MainWindow *ui;
Test *m_test;
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "test.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
m_test = new Test();
m_test->slotFlex(this, &MainWindow::testSlots);
m_test->test();
}
MainWindow::~MainWindow() { delete ui; }
void MainWindow::testSlots(int a) { qDebug() << "slot flex" << a; }
原理就是使用typedef QtPrivate::FunctionPointer<Func>获取函数信息,包括参数,返回值等,生成一个slotObject对象,然后调用call方法。
QSlotObject是 QtPrivate::QSlotObjectBase的子对象,将impl方法传递给父类,QtPrivate::QSlotObjectBase调用impl方法
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
{
switch (which) {
case Destroy:
delete static_cast<QSlotObject*>(this_);
break;
case Call:
FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
break;
case Compare:
*ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function;
break;
case NumOperations: ;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。