背景知识:

基类 superClass

class superClass
{
public:
superClass()
{
std::string m = "superClass() " + std::to_string((long)this) + "\n";
std::cout << m << std::endl;
}
virtual ~superClass()
{ std::string m = "~superClass " + std::to_string((long)this) + "\n";
std::cout << m << std::endl;
} virtual void print() const
{
std::string m = "printsuperClass " + std::to_string((long)this) + "\n" ;
std::cout << m << std::endl;
}
virtual void setA(int v_) const { } private:
int a = ;
};

子类subClass

class subClass : public superClass
{
public:
subClass():superClass(){ std::cout << "subClass()" << std::endl; }
~subClass()
{
std::cout << "~subClass" << std::endl;
} void print()
{
std::cout << "subclass print " << std::endl;
} void test()
{
std::cout << "test" << std::endl;
}
};

生产者 生产子类,然后通过信号传递出去。消费者订阅生产者的信号,然后消费子类。

当生产者和消费者都在同一线程的时候:

mysignal(cn)

会被复制

复制次数 =消费者个数

mysignal(cn &)

不会被复制

mysignal(const cn &)

不会被复制

by value  same thread

superClass()
printsuperClass
~superClass
printsuperClass
~superClass
printsuperClass
~superClass
~superClass
~superClass

当生产者和消费者均在不同线程时:

mysignal(cn)

会被复制

复制次数 =消费者个数*2

mysignal(cn &)

不可用于多线程

mysignal(const cn &)

会被复制

复制次数=消费者个数

by value different

superClass()
printsuperClass
~superClass
printsuperClass
~superClass
printsuperClass
~superClass
~superClass
~superClass
~superClass
~superClass
~superClass

解决方案1:

生产者和消费者在同一线程,那么只能按照生产一个消费一个的模式工作。

Signal的定义可以为:

signals:
void mysignal(superClass &);

该签名只能用于单线程模式。

多线程模式下:

signals:
void mysignal(superClass);

该模式下,消费者端代码如下:

public slots:
void consume(superClass sc)
{
subClass & sub = (subClass &)(sc);
sub.print();
}

或者

signals:
void mysignal(const superclass &);

该模式下,消费者端代码如下:

public slots:
void consume(const superClass & sc)
{
superClass temp = sc;
subClass & sub = (subClass &)(temp);
sub.print();
}

此时,sub调用的是父类的print方法。

解决方案二:

在子类中添加一个通过父类来构造子类的构造方法:

class subClass : public superClass
{
public:
subClass():superClass(){ std::cout << "subClass()" << std::endl; } subClass(const superClass & s):subClass()
{
std::cout << "construct subClass from superClass()" << std::endl;
} ~subClass()
{
std::cout << "~subClass" << std::endl;
} void print() override
{
std::cout << "subClass" << a << std::endl;
} void setA(int v_) { a = v_; } void test()
{
std::cout << "test" << std::endl;
} private:
int a = ;
};

生产者如下生产:

    void produce()
{
subClass sub;
sub.setA();
emit mysignal(sub);
}

消费者如下消费:

    void consume(const superClass & sc)
{
subClass sub = sc;
sub.print();
}

但此时subClass中的a信息已经丢失。

解决方案三:

改用指针,方法签名为:

signals:
void mysignal(superClass *);

生产者如下生产:

    void produce()
{
subClass * sub = new subClass();
sub->setA();
emit mysignal(sub);
}

消费者如下消费:

    void consume(superClass * sc)
{
subClass * sub = dynamic_cast<subClass *>(sc);
sub->print();
}

但是在有多个消费者的时候,

    connect(&p, SIGNAL(mysignal(superClass *)), &c, SLOT(consume(superClass *)));
connect(&p, SIGNAL(mysignal(superClass *)), &c2, SLOT(consume(superClass *)));

没有消费者适合删除指针。必然导致内存泄漏。一旦有消费者删除了指针,则其他未消费的消费者将崩溃。这样的设计有一个隐患,一个消费者的恶意代码可以搞垮其他消费者。

解决方案四:

放弃QT 信号机制,自己实现ResultHandler,所有的消费者通过register方式将直接的消费方式注册到统一的地方,由一个地方统一调用。这样的话,各个线程的方法会排队执行,失去多线程的意义。

综上,放弃父类子类设计方式。由统一一个类来实现所有功能。但是传递对象有效率问题,因为有多少个消费者,就会复制多少份对象。

爱恨难取舍。

基类子类在Qt信号量机制下的思考的更多相关文章

  1. Qt事件处理机制

    研一的时候开始使用Qt,感觉用Qt开发图形界面比MFC的一套框架来方便的多.后来由于项目的需要,也没有再接触Qt了.现在要重新拾起来,于是要从基础学起. Now,开始学习Qt事件处理机制. 先给出原文 ...

  2. Qt 事件处理机制

    Qt 事件处理机制 因为这篇文章写得特别好,将Qt的事件处理机制能够阐述的清晰有条理,并且便于学习.于是就装载过来了(本文做了排版,并删减了一些冗余的东西,希望原主勿怪),以供学习之用. 简介 在Qt ...

  3. 关于C#基类和子类函数调用问题

    c#基类子类的函数调用关系,代码说明newkeyword后面的类中的函数为对象调用的函数,当然必需要有virtual和override,继承就相当于包括了基类的函数,子类对象调用时基类的函数相当于就在 ...

  4. RTTI、虚函数和虚基类的实现方式、开销分析及使用指导(虚函数的开销很小,就2次操作而已)

    白杨 http://baiy.cn “在正确的场合使用恰当的特性” 对称职的C++程序员来说是一个基本标准.想要做到这点,首先要了解语言中每个特性的实现方式及其开销.本文主要讨论相对于传统 C 而言, ...

  5. 构造函数为什么不能为虚函数 &amp; 基类的析构函数为什么要为虚函数

    一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数 ...

  6. 读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字

    1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会 ...

  7. python3+selenium框架设计04-封装测试基类

    在完成了日志类封装之后,那我们就要对测试基类进行实现,在其中对一些请求再次封装,在项目下新建一个framework文件夹,在文件夹下新建Base_Page.py文件,这是用来写测试基类的文件.在项目下 ...

  8. c++ 基类,派生类的类型兼容性

    #include <iostream> using namespace std; class CFather { public: void display() const { cout&l ...

  9. mfc 基类与子类

    基类(父类) 派生类(子类) 一.基类(父类) 基类(又称为父类,基类与派生类是相对的关系! 通过继承机制,可以利用已有的数据类型来定义新的数据类型.所定义的新的数据类型不仅拥有新定义的成员,而且还同 ...

随机推荐

  1. 【NOIP2012模拟10.25】旅行

    题目 给定一个n行m列的字符矩阵,'.'代表空地,'X'代表障碍.移动的规则是:每秒钟以上下左右四个方向之一移动一格,不能进入障碍. 计算:在空地中随机选择起点和终点(可以重合,此时最短耗时为0),从 ...

  2. 【shell】sed指定追加模式空间的次数

    最近遇到一个文本复制的场景,需要把文本的每一行都重复输出三次. 这个用awk或者sed实现都还是很简单的. sed代码: [root]$ seq | sed '{h;G;G}' 现在的问题是,如果每行 ...

  3. 百分号编码(URL编码)

    百分号编码又叫做URL编码,是一种编码机制,只要用于URI(包含URL和URN)编码中. URL中那些字符需要编码,又为什么进行编码 一.URL是什么?  URL(Uniform Resource L ...

  4. 使用swagger生成API说明文档

    使用swagger生成API说明文档本文由个人总结,如需转载使用请标明原著及原文地址没有导出!!!!!不要整天给我留言导出呢,那个是你们百度的时候下面的推荐文章带的关键字,要做导出从swagger取数 ...

  5. python3学习笔记(三):注释和字符串

    一.注释 为了让别人能够更容易理解程序,使用注释是非常有效的,即使是自己回头再看旧代码也是一样. # 打印圆的周长: print(2* pi* r) 在python 中用井号(#)表示注释.井号(#) ...

  6. pycharm selenium 安装firefox驱动和Google驱动教程

    一.下载Firefox浏览器或Google浏览器 下载渠道有很多,直接下载最新版的就可以了. 二.下载驱动 Firefox驱动 地址:https://github.com/mozilla/geckod ...

  7. 阿里云OSS文件上传封装

    1.先用composer安装阿里云OSS的PHPSDK 2.配置文件里定义阿里云OSS的秘钥 3.在index控制器里的代码封装 <?php namespace app\index\contro ...

  8. swagger2简单使用

    1.引入jar <!--引入swagger--> <dependency> <groupId>io.springfox</groupId> <ar ...

  9. maven依赖传递和排除依赖冲突

    1 依赖的传递 假如 A项目 依赖 a.jar 1.0.1,b.jar 1.0.1,没有直接依赖c.jar 1.0.1,但是b.jar 1.0.1依赖了c.jar 1.0.1,可以说A项目间接依赖了c ...

  10. Git-Runoob:Git 工作区、暂存区和版本库

    ylbtech-Git-Runoob:Git 工作区.暂存区和版本库 1.返回顶部 1. Git 工作区.暂存区和版本库 基本概念 我们先来理解下Git 工作区.暂存区和版本库概念 工作区:就是你在电 ...