背景知识:
基类 superClass
class superClass { public: superClass(){ std::cout << "superClass()" << std::endl; } virtual ~superClass(){} virtual void print() { std::cout << "superclass print " << std::endl; } };
子类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 &) |
单,多线程 |
会被复制 |
解决方案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 = 0; };
生产者如下生产:
void produce() { subClass sub; sub.setA(100); 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(100); 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方式将直接的消费方式注册到统一的地方,由一个地方统一调用。这样的话,各个线程的方法会排队执行,失去多线程的意义。
综上,放弃父类子类设计方式。由统一一个类来实现所有功能。但是传递对象有效率问题,因为有多少个消费者,就会复制多少份对象。
爱恨难取舍。
时间: 2024-10-10 10:00:21