概述
目录
QT信号槽
模拟思路
核心类说明
object.h
object.cpp
msg.h
消息绑定验证
ClassA.h
ClassA.cpp
ClassB.h
ClassB.cpp
MainClass.h
MainClass.cpp
main.cpp
部分打印信息
QT信号槽
C++模仿信号槽之前,需要了解一下QT信号槽实现机制
继承自QObject的类添加Q_OBJECT宏后,引用了元对象系统(QMetaObject)并定义了相关对象及行为函数,
使用connect绑定的信号槽相关信息(sender,signal_index,receiver,slot_index)都保存在每个类的元对象系统中,
emit发送信号时实际调用的是moc生成的信号定义函数,激活信号,
最后找到元对象系统中该信号绑定的相应槽函数(可多个),然后执行槽函数。
模拟思路
基类Object,提供connect、emit接口,需要互相传递消息的类需要继承Object
消息激活类MsgActivator,该类保存着消息与注册该消息的map
基类中的HandleMsg(const AbstractMsg &msg)接口,是每个继承Object的实例处理消息的接口
AbstractMsg消息类,所有消息体都要继承该消息类
OBJECT宏,继承Object的类若需要消息传递,则需添加OBJECT宏,该宏会定义消息激活类的实例
核心类说明
object.h
#pragma once
#include "msg.h"
#include <thread>
#include <mutex>
using namespace Msg;
#define SIGNALS public
/*
* OBJECT宏,在继承Object类中添加,开启消息绑定发送功能
*/
#define OBJECT
MsgActivator dis;
std::mutex m_dMutex;
void SubToSender(MsgType mt, Object *receiver) override
{
dis.m_mMsgInfo[mt].push_back(receiver);
}
void SubToSenderThread(MsgType mt, Object *receiver) override
{
std::lock_guard<std::mutex> locker(m_dMutex);
dis.m_mMsgInfoThread[mt].push_back(receiver);
}
void PubToSuber(const AbstractMsg &msg) override
{
dis.activate(msg);
}
class Object;
class MsgActivator
{
SIGNALS:
void activate(const AbstractMsg &msg);
std::map<MsgType, std::vector<Object*>> m_mMsgInfo;
std::map<MsgType, std::vector<Object*>> m_mMsgInfoThread;
};
class Object
{
public:
Object();
~Object();
std::thread::id CurrentThread();
// 消息绑定,支持多线程
static void connect(Object *sender,MsgType mt, Object *receiver);
// 消息绑定,支持多线程
void connect(Object *sender,MsgType mt);
// 发送消息
void emit(const AbstractMsg &msg);
// 处理消息
virtual bool HandleMsg(const AbstractMsg &msg);
protected:
// 在OBJECT宏中重写,同一线程使用,connect之后将接收者实例传递给发送者按消息类型保存
virtual void SubToSender(MsgType mt, Object *receiver);
// 在OBJECT宏中重写,同SubToSender,在多线程中被connect调用
virtual void SubToSenderThread(MsgType mt, Object *receiver);
// 在OBJECT宏中重写,被emit调用
virtual void PubToSuber(const AbstractMsg &msg);
private:
std::thread::id m_dThreadId;
};
object.cpp
#include "Object.h"
Object::Object()
: m_dThreadId(std::this_thread::get_id())
{
}
Object::~Object()
{
}
std::thread::id Object::CurrentThread()
{
return m_dThreadId;
}
void Object::connect(Object *sender,MsgType mt)
{
connect(sender,mt,this);
}
void Object::emit(const AbstractMsg &msg)
{
PubToSuber(msg);
}
void Object::SubToSender(MsgType mt, Object *receiver)
{
}
void Object::SubToSenderThread(MsgType mt, Object *receiver)
{
}
void Object::PubToSuber(const AbstractMsg &msg)
{
}
bool Object::HandleMsg(const AbstractMsg &msg)
{
return false;
}
void Object::connect(Object *sender,MsgType mt, Object *receiver)
{
if (sender->CurrentThread() == receiver->CurrentThread())
sender->SubToSender(mt,receiver);
else
sender->SubToSenderThread(mt, receiver);
}
void MsgActivator::activate(const AbstractMsg &msg)
{
std::vector<Object*> &subers = m_mMsgInfo[msg.m_dMsgType];
for(Object *sub : subers) {
sub->HandleMsg(msg);
}
std::vector<Object*> &subersThread = m_mMsgInfoThread[msg.m_dMsgType];
for(Object *sub : subersThread) {
sub->HandleMsg(msg);
}
}
msg.h
#pragma once
#include <map>
#include <vector>
#include <string>
#include <memory>
#include <iostream>
#include <algorithm>
using namespace std;
namespace Msg {
// 消息类型
enum MsgType {
MT_None,
MT_A,
MT_B,
MT_C,
};
// 消息基类
struct AbstractMsg
{
AbstractMsg(MsgType mt = MT_None):m_dMsgType(mt){}
MsgType Type() {
return m_dMsgType;
}
MsgType m_dMsgType;
};
// MsgA消息
struct MsgA : AbstractMsg
{
MsgA():AbstractMsg(MT_A){}
int a;
std::string b;
double c;
};
//MsgB消息
struct MsgB : AbstractMsg
{
MsgB():AbstractMsg(MT_B){}
int a;
std::string b;
double c;
};
};
消息绑定验证
ClassA.h
#pragma once
#include "Object.h"
class ClassA : public Object
{
OBJECT
public:
ClassA();
~ClassA();
void testA(int val = 1);
bool HandleMsg(const AbstractMsg &msg) override;
};
ClassA.cpp
#include "ClassA.h"
ClassA::ClassA()
{
}
ClassA::~ClassA()
{
}
void ClassA::testA(int val)
{
MsgA a;
a.a = val;
a.b = "testA";
a.c = 1.1;
emit(a);
}
bool ClassA::HandleMsg(const AbstractMsg &msg)
{
switch (msg.m_dMsgType)
{
case MT_A:
{
const MsgA& _msg = static_cast<const MsgA&>(msg);
cout << "thread:" << CurrentThread() << " ClassA recv MT_A msg:" <<
"a=" << _msg.a << " b=" << _msg.b << " c=" << _msg.c << endl;
}
break;
case MT_B:
{
const MsgB& _msg = static_cast<const MsgB&>(msg);
cout << "thread:" << CurrentThread() << " ClassA recv MT_B msg:" <<
"a=" << _msg.a << " b=" << _msg.b << " c=" << _msg.c << endl;
}
break;
case MT_C:
break;
default:
break;
}
return true;
}
ClassB.h
#pragma once
#include "Object.h"
class ClassB : public Object
{
OBJECT
public:
ClassB();
~ClassB();
void testB(int val = 1);
bool HandleMsg(const AbstractMsg &msg) override;
};
ClassB.cpp
#include "ClassB.h"
ClassB::ClassB()
{
}
ClassB::~ClassB()
{
}
void ClassB::testB(int val)
{
MsgB b;
b.a = val;
b.b = "testB";
b.c = 1.1;
emit(b);
}
bool ClassB::HandleMsg(const AbstractMsg &msg)
{
switch (msg.m_dMsgType)
{
case MT_A:
{
const MsgA& _msg = static_cast<const MsgA&>(msg);
cout << "ClassB recv MT_A msg:" <<
"a=" << _msg.a << " b=" << _msg.b << " c=" << _msg.c << endl;
}
break;
case MT_B:
{
const MsgB& _msg = static_cast<const MsgB&>(msg);
cout << "ClassB recv MT_B msg:" <<
"a=" << _msg.a << " b=" << _msg.b << " c=" << _msg.c << endl;
}
break;
case MT_C:
break;
default:
break;
}
return true;
}
MainClass.h
#pragma once
#include "Object.h"
#include "ClassA.h"
#include "ClassB.h"
class MainClass : public Object
{
OBJECT
public:
MainClass();
~MainClass();
void test();
static void testThread(void *);
bool HandleMsg(const AbstractMsg &msg) override;
private:
void InitMain();
private:
ClassA *m_pClassA;
ClassB *m_pClassB;
};
MainClass.cpp
#include "MainClass.h"
#include <memory>
#include <condition_variable>
#include <atomic>
std::mutex g_mtx;
std::condition_variable g_cv;
std::atomic_bool g_bool;
void testThread2(void *arg)
{
MainClass *_this = static_cast<MainClass*>(arg);
if (_this)
{
for (int i(0); i<1000; i++)
{
std::unique_lock<std::mutex> lk(g_mtx);
/*
*该种阻塞方式可以减少CPU占用
*如果是单纯的用while,不断轮询会让CPU占用升高
*而使用条件变量的方式,wait会让出时间片
*在notify_all通知后会再次占用CPU
*/
while (!g_bool.load())
g_cv.wait(lk);
std::shared_ptr<ClassA> p(new ClassA);
Object::connect(p.get(),MT_A,_this);
p->testA(i);
g_bool.store(false);
g_cv.notify_all();
}
}
}
void MainClass::testThread(void *arg)
{
MainClass *_this = static_cast<MainClass*>(arg);
if (_this)
{
for (int i(0); i<1000; i++)
{
std::unique_lock<std::mutex> lk(g_mtx);
while (g_bool.load())
g_cv.wait(lk);
std::shared_ptr<ClassB> p(new ClassB);
Object::connect(p.get(),MT_B,_this);
p->testB(i);
g_bool.store(true);
g_cv.notify_all();
}
}
}
MainClass::MainClass()
: m_pClassA(nullptr)
, m_pClassB(nullptr)
{
InitMain();
}
MainClass::~MainClass()
{
if (m_pClassA)
{
delete m_pClassA;
m_pClassA = nullptr;
}
if (m_pClassB)
{
delete m_pClassB;
m_pClassB = nullptr;
}
}
void MainClass::test()
{
m_pClassA->testA();
m_pClassB->testB();
cout << "THIS:" << CurrentThread() << endl;
std::thread t1(&MainClass::testThread,(void*)this);
std::thread t2(testThread2,(void*)this);
// for (int i(0); i<1000; i++)
// {
// std::shared_ptr<ClassA> p(new ClassA);
// Object::connect(p.get(),MT_A,this);
// p->testA();
// }
t1.join();
t2.join();
}
bool MainClass::HandleMsg(const AbstractMsg &msg)
{
switch (msg.m_dMsgType)
{
case MT_A:
{
const MsgA& _msg = static_cast<const MsgA&>(msg);
cout << "MainClass recv MT_A msg:" <<
"a=" << _msg.a << " b=" << _msg.b << " c=" << _msg.c << endl;
}
break;
case MT_B:
{
const MsgB& _msg = static_cast<const MsgB&>(msg);
cout << "MainClass recv MT_B msg:" <<
"a=" << _msg.a << " b=" << _msg.b << " c=" << _msg.c << endl;
}
break;
case MT_C:
break;
default:
break;
}
return true;
}
void MainClass::InitMain()
{
m_pClassA = new ClassA;
m_pClassB = new ClassB;
connect(m_pClassA,MT_A);
connect(m_pClassB,MT_B);
}
main.cpp
#include "MainClass.h"
int main()
{
MainClass mainclass;
mainclass.test();
return 0;
}
部分打印信息
MainClass recv MT_B msg:a=70 b=testB c=1.1
MainClass recv MT_A msg:a=70 b=testA c=1.1
MainClass recv MT_B msg:a=71 b=testB c=1.1
MainClass recv MT_A msg:a=71 b=testA c=1.1
MainClass recv MT_B msg:a=72 b=testB c=1.1
MainClass recv MT_A msg:a=72 b=testA c=1.1
MainClass recv MT_B msg:a=73 b=testB c=1.1
MainClass recv MT_A msg:a=73 b=testA c=1.1
MainClass recv MT_B msg:a=74 b=testB c=1.1
MainClass recv MT_A msg:a=74 b=testA c=1.1
MainClass recv MT_B msg:a=75 b=testB c=1.1
MainClass recv MT_A msg:a=75 b=testA c=1.1
MainClass recv MT_B msg:a=76 b=testB c=1.1
MainClass recv MT_A msg:a=76 b=testA c=1.1
MainClass recv MT_B msg:a=77 b=testB c=1.1
MainClass recv MT_A msg:a=77 b=testA c=1.1
MainClass recv MT_B msg:a=78 b=testB c=1.1
MainClass recv MT_A msg:a=78 b=testA c=1.1
MainClass recv MT_B msg:a=79 b=testB c=1.1
MainClass recv MT_A msg:a=79 b=testA c=1.1
MainClass recv MT_B msg:a=80 b=testB c=1.1
MainClass recv MT_A msg:a=80 b=testA c=1.1
MainClass recv MT_B msg:a=81 b=testB c=1.1
MainClass recv MT_A msg:a=81 b=testA c=1.1
MainClass recv MT_B msg:a=82 b=testB c=1.1
MainClass recv MT_A msg:a=82 b=testA c=1.1
MainClass recv MT_B msg:a=83 b=testB c=1.1
MainClass recv MT_A msg:a=83 b=testA c=1.1
MainClass recv MT_B msg:a=84 b=testB c=1.1
MainClass recv MT_A msg:a=84 b=testA c=1.1
MainClass recv MT_B msg:a=85 b=testB c=1.1
最后
以上就是清秀砖头为你收集整理的C++写一个信号槽的全部内容,希望文章能够帮你解决C++写一个信号槽所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复