在Qt的开发中核心之一就是信号与槽的设计,它们的具体概念我就不多叙述了,可以看看IBM的这篇文章讲的很清楚——《Qt的信号与槽机制介绍》。有一些Windows开发经验的角度来看,信号与槽机制就像windows的消息机制,发射消息就是相当于像操作系统发送消息,槽函数的实现就相当于消息响应函数的实现,当然,Qt中是一个线程实现的传递,而在windows中则是操作系统实现的。
今天我不详细讲解一下信号与槽的具体用法,只是说明一下在用法上的一个误区,网上很多文章对它的简单用法的说明,比如《Qt的信号与槽机制介绍》这篇文章上,对信号的声明:
signals:
void mySignal();
void mySignal(int x);
void mySignalParam(int x,int y);
对槽函数的声明:
public slots:
void mySlot();
void mySlot(int x);
void mySignalParam(int x,int y);
再把信号和槽连接起来就能完成,最后对槽函数实现一下就OK。
但是如果信号与槽传递的是我们自定义的类型或者是非基本类型呢?比如说是QVector容器等数据。很多人就会说了,那我把它们作为形参传递进来不久OK了,下面我们试一下。
class RecognitionData {
private:QImage* m_recogImage;QString m_recogAngle;}
这是一个简单的自定义类型,我们先实例化一个对象,然后声明以它作为形参的信号与槽,最后把信号与槽连接起来。
RecognitionData data();
signals:
void mySignal(RecognitionData);
public slots:
void mySloy(RecognitionData);
但是当我们发射这个信号的时候却发现槽函数根本没有响应,这是为什么呢?
我当时遇到这个问题之后就得是不是声明和使用有问题,因为在连接信号与槽的时候,编译器不会检查是否存在这个信号与槽。很认真的检查了几遍之后发现没有错,那这是为什么呢?当时很不明白,纠结了很长时间,网上也没有说法。
最后我抱着试试的态度,把信号和槽的参数设置为自定义类或者是非基本类型的指针,比如:
RecognitionData data();
signals:
void mySignal(RecognitionData *);
public slots:
void mySloy(RecognitionData *);
奇迹发生了,槽函数居然进行了响应,这样我就得到了一个结论,信号与槽传递时只能传递最基本的类型或者是指针,但是想想为什么会有这么个限制呢,难道Qt的设计团队没有想到这个问题,显然不可能。
仔细想想整个流程发现,如果将实例化的对象作为信号和槽的形参传递,在槽函数还没开始执行的时候,传递的这个实例化的对象已经在发射信号之后销毁了,槽函数就没法访问到这个对象,那它怎么可能会执行呢?原来如此啊!
但是指针为什么能行呢?这就是指针跟实例对象的区别,指针指向的内存块是在堆内存中,不手动销毁的话程序是不会自动销毁的,而实例化的对象则不一样,它是在栈中实例化的,在它的作用域结束之后,程序会自动将它销毁掉。
终于弄明白了以上的问题,感慨啊,一个小小的问题还涉及到这么多机制,值得说明的是,如果以指针作为形参传递的话,在槽函数中一定要去释放这个指针指向的内存,否则就会出现内存泄露。