我是靠谱客的博主 清秀砖头,最近开发中收集的这篇文章主要介绍C++写一个信号槽,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

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++写一个信号槽所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部