基类子类在Qt信号量机制下的思考
背景知识:
基类 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信号量机制下的思考的更多相关文章
- Qt事件处理机制
研一的时候开始使用Qt,感觉用Qt开发图形界面比MFC的一套框架来方便的多.后来由于项目的需要,也没有再接触Qt了.现在要重新拾起来,于是要从基础学起. Now,开始学习Qt事件处理机制. 先给出原文 ...
- Qt 事件处理机制
Qt 事件处理机制 因为这篇文章写得特别好,将Qt的事件处理机制能够阐述的清晰有条理,并且便于学习.于是就装载过来了(本文做了排版,并删减了一些冗余的东西,希望原主勿怪),以供学习之用. 简介 在Qt ...
- 关于C#基类和子类函数调用问题
c#基类子类的函数调用关系,代码说明newkeyword后面的类中的函数为对象调用的函数,当然必需要有virtual和override,继承就相当于包括了基类的函数,子类对象调用时基类的函数相当于就在 ...
- RTTI、虚函数和虚基类的实现方式、开销分析及使用指导(虚函数的开销很小,就2次操作而已)
白杨 http://baiy.cn “在正确的场合使用恰当的特性” 对称职的C++程序员来说是一个基本标准.想要做到这点,首先要了解语言中每个特性的实现方式及其开销.本文主要讨论相对于传统 C 而言, ...
- 构造函数为什么不能为虚函数 & 基类的析构函数为什么要为虚函数
一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数 ...
- 读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字
1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会 ...
- python3+selenium框架设计04-封装测试基类
在完成了日志类封装之后,那我们就要对测试基类进行实现,在其中对一些请求再次封装,在项目下新建一个framework文件夹,在文件夹下新建Base_Page.py文件,这是用来写测试基类的文件.在项目下 ...
- c++ 基类,派生类的类型兼容性
#include <iostream> using namespace std; class CFather { public: void display() const { cout&l ...
- mfc 基类与子类
基类(父类) 派生类(子类) 一.基类(父类) 基类(又称为父类,基类与派生类是相对的关系! 通过继承机制,可以利用已有的数据类型来定义新的数据类型.所定义的新的数据类型不仅拥有新定义的成员,而且还同 ...
随机推荐
- 【NOIP2017模拟6.25】小W的动漫
题目 小W最近迷上了日本动漫,每天都有无数部动漫的更新等着他去看,所以他必须将所有的动漫排个顺序,当然,虽然有无数部动漫,但除了1号动漫,每部动漫都有且仅有一部动漫是它的前传(父亲),也就是说,所有的 ...
- vue 设置 input 为不可以编辑
我用最笨的方法,先实现功能先,用两个input,一个可以编辑,一个不可以编辑,失去焦点后隐藏可以点击的那个,点"编辑"时,显示可以编辑的那个input <div class= ...
- electron监听系统托盘,electron是否最小化到系统托盘
在项目中需要判断窗口是否最小化在系统托盘上,任务栏那已经关闭,查了一晚上的api,始终找不到可以调用的方法,最后绞尽脑汁想到了一个办法,那就是在点右上角的关闭按钮时,加个全局变量,用来标识已经最小到系 ...
- 【leetcode】1172. Dinner Plate Stacks
题目如下: You have an infinite number of stacks arranged in a row and numbered (left to right) from 0, e ...
- ubuntu 7z解压
安装方法: sudo apt-get install p7zip 解压文件: 7z x manager.7z -r -o /home/xx 解释如下: x 代表解压缩文件,并且是按原始 ...
- Java多线程的创建方法
Java 线程类也是一个 object 类,它的实例都继承自java.lang.Thread 或其子类. 可以用如下方式用 java 中创建一个线程,执行该线程可以调用该线程的 start()方法: ...
- windows下 申请免费ssl证书的方法 (letsencrypt)
Let's Encrypt,官网是https://letsencrypt.org/,它是一个由各大公司赞助的公益组织: 有趋势有需求,自然也有免费可用.免费的SSL证书中,首推就是Let's Encr ...
- Oracle数据库链接超级慢或者总提示链接超时
Centos6 今天tomcat应用程序链接数据库总提示链接超时,客户端工具通过tnsnames连接数据库实例进行操作也超级慢, 实在无法忍受, 重启实例试试吧,重启了还是不好使,还是很慢很慢,无比 ...
- 关于kafka在windows上的安装、运行
一.安装kafka 下载地址:http://kafka.apache.org/downloads 要下载Binary downloads这个类型,不要下载源文件,这种方便使用.下载后,解压放在D ...
- Servlet的常见错误
Servlet常见的错误: 1.404错误:资源未找到 原因一:在请求地址中的servlet的别名书写错误. 原因二:虚拟机项目名称拼写错误. 2.500错误:内部服务器错误 错误一: java.la ...