第三回 父与子

70后的道友都应该看过这么一部片子叫做<<父子情深>>。讲述的是一个小男孩患了绝症,父亲为了满足他的愿望,让已关门的游乐园为他们父子俩重新开放。在游乐园尽情地玩耍后,最后小孩子在父亲的怀中安详地闭上了眼睛。缓缓转动的摩天轮,配着淡淡忧伤的曲调,这一刻哥泪流满面。谁说世上只有妈妈好,父爱也顶半边天。此时台下的众多男道友热泪盈眶,不约而同地起立鼓掌。史上最大的冤屈,终于得以昭雪。

但是人世间这种真挚的父爱也存在于Qt中吗? 对此,从小缺乏父爱的张无忌小友给出了自己的答案,

01 #include <QDebug>
02 #include <QThread>
03  
04 class MyTestA : public QObject
05 {
06 Q_OBJECT
07 public:
08  
09 };
10  
11 class MyTestB : public QObject
12 {
13 public:
14 MyTestB(QObject *parent):QObject(parent)
15 {
16  
17 }
18 };
19  
20 extern MyTestB *g_pMyTestB;
21 extern MyTestA *g_pMyTestA;
22 class MyTestC : public QThread
23 {
24 Q_OBJECT
25 public:
26  
27 MyTestC():QThread(NULL)
28 {
29 }
30  
31 void run()
32 {
33 exec();
34 }
35 };
36 int main(int argc, char *argv[])
37 {
38 QApplication app(argc, argv);
39  
40 MyTestA a;
41  
42 MyTestB b(&a);
43  
44 MyTestC c;
45 c.start();
46  
47 a.moveToThread(&c);
48 if(a.thread() == b.thread() && a.thread()!=app.thread())
49 {
50 qDebug()<< "Both parent and son have the same thread";
51 }
52  
53 return app.exec();
54 }

从容地按下了F5之后,只见输出窗口妥妥地输出了"Both parent and son have the same thread".

在Qt中,当一个对象被移到另一个线程时,他的所有子对象也会一并转移到另外那个线程。

一人移民,全家无忧阿。在场的一些兼职移民中介的道友叹道,简直就是一个经典的家庭移民案例。不愧是家有一父,如有一宝啊。

紧接着只见张无忌,对此代码稍作了修改,

01 class MyTestA : public QObject
02 {
03 Q_OBJECT
04 public:
05 };
06  
07 class MyTestB : public QObject
08 {
09 public:
10 MyTestB(QObject *parent):QObject(parent)
11 {
12  
13 }
14 };
15  
16 extern MyTestB *g_pMyTestB;
17 extern MyTestA *g_pMyTestA;
18 class MyTestC : public QThread
19 {
20 Q_OBJECT
21 public:
22  
23 MyTestC():QThread(NULL)
24 {
25 }
26  
27 void run()
28 {
29 g_pMyTestA->moveToThread(this);
30 exec();
31 }
32 };
33  
34 MyTestB *g_pMyTestB = NULL;
35 MyTestA *g_pMyTestA = NULL;
36 int main(int argc, char *argv[])
37 {
38 QApplication app(argc, argv);
39  
40 MyTestA a;
41 g_pMyTestA = &a;
42  
43 MyTestB b(&a);
44  
45 MyTestC c;
46 c.start();
47  
48 return app.exec();
49 }

却见output窗口打出,

"QObject::moveToThread: Current thread (0x2ff944) is not the object's thread (0x357b20).
Cannot move to target thread (0x2ff944)"

在Qt中,如果要切换对象的线程,不能到了目标线程里再调用moveToThread,此举会导致切换线程失败。

众人皆称,移民要合法,偷渡要不得啊。

就在众人嗟叹时,年轻气盛的无忌小友,又刷刷的写下了以下代码,

001 #include <QThread>
002  
003 class MyTestA : public QObject
004 {
005 Q_OBJECT
006 public:
007  
008 };
009  
010 class MyTestB : public QObject
011 {
012 public:
013 MyTestB(QObject *parent):QObject(parent)
014 {
015 }
016 };
017  
018 extern MyTestB *g_pMyTestB;
019 extern MyTestA *g_pMyTestA;
020 class MyTestC : public QThread
021 {
022 Q_OBJECT
023 public:
024  
025 MyTestC(QObject *parent):QThread(parent)
026 {
027 }
028 };
029  
030  
031 class MyTest : public QDialog
032 {
033 Q_OBJECT
034  
035 public:
036 MyTest(QWidget *parent = 0, Qt::WFlags flags = 0);
037 ~MyTest();
038  
039 protected slots:
040 void onClick();
041  
042  
043 private:
044 Ui::MyTestClass ui;
045 };
046 /////////////////////////////////////////
047 MyTest::MyTest(QWidget *parent,
Qt::WFlags flags)
048 :
QDialog(parent, flags)
049 {
050 ui.setupUi(this);
051 //set
the window to be the top window
052 <SPAN
style=
"COLOR: #ff0000">this->setWindowFlags(windowFlags()|Qt::WindowStaysOnTopHint);</SPAN>
053 }
054  
055 MyTest::~MyTest()
056 {
057  
058 }
059  
060 void MyTest::onClick()
061 {
062 <SPAN
style=
"COLOR: #ff0000">QMessageBox box(this);</SPAN>
063 box.setText("i am at the
top"
);
064 box.exec();
065 }
066  
067 //////////////////main.cpp///////////////////////
068 MyTestB *g_pMyTestB = NULL;
069 MyTestA *g_pMyTestA = NULL;
070 int main(int argc, char *argv[])
071 {
072 QApplication app(argc, argv);
073  
074  
075  
076 MyTestA
a;
077  
078 <SPAN
style=
"COLOR: #ff0000">MyTestB *pB = new MyTestB(&a);</SPAN>
079 <SPAN
style=
"COLOR: #ff0000"> pB->setObjectName("MyTestB");</SPAN>
080  
081 <SPAN
style=
"COLOR: #ff0000"> MyTestC *pC = new MyTestC(&a);</SPAN>
082 <SPAN
style=
"COLOR: #ff0000">pC->setObjectName("MyTestC");</SPAN>
083  
084 <SPAN
style=
"COLOR: #ff0000">pC = new MyTestC(&a);</SPAN>
085 <SPAN
style=
"COLOR: #ff0000">pC->setObjectName("MyTestC1");</SPAN>
086  
087 <SPAN
style=
"COLOR: #ff0000">QList<QObject*> list =
a.findChildren<QObject*>();</SPAN>
088 QList<QObject*>::iterator it;
089 qDebug()<<"All the son
list: "
<<"\r\n";
090 for(it = list.begin();
it != list.end() ; it++)
091 {
092 qDebug()<<(*it)->objectName()<<"\r\n";
093 }
094 qDebug()<<"============================"<<"\r\n";
095  
096  
097 <SPAN
style=
"COLOR: #ff0000">QList<MyTestC*> listC =
a.findChildren<MyTestC*>();</SPAN>
098 QList<MyTestC*>::iterator itC;
099 qDebug()<<"MyTestC list:
"
<<"\r\n";
100 for(itC = listC.begin();
itC != listC.end() ; itC++)
101 {
102 qDebug()<<(*itC)->objectName()<<"\r\n";
103 }
104 qDebug()<<"============================"<<"\r\n";
105  
106 <SPAN
style=
"COLOR: #ff0000"> MyTestC *pC1 = a.findChild<MyTestC*>("MyTestC1");</SPAN>
107 if(pC1)
108 {
109 qDebug()<<"MyTestC1 has
been found"
<<"\r\n";
110 }
111  
112 MyTest
win;
113 win.show();
114  
115 return app.exec();
116 }

然后销魂的转身一点,只见

在Qt中,我们可以通过findChild,findChildren,qFindChild,qFindChildren,来遍历所有的子对象,同时我们可以通过指定类型,来得到所有的指定类型的子对象,当然也可以通过对象名字来索引。比如m_dlg.findChildren<QPushButton*>();通过这个函数我们可以轻松的遍历出对话框中所有的QPushButton子对象,这样对我们诸如换语言的操作提供了便利。换句话说,Qt的父对象也起到了一个容器的作用,我们有时可以利用这一点,把父对象作为一个容器处理。

众人不禁赞道,知子莫如父啊。

无忌小友看在眼里,喜在心头。只见他又继续点击F5,弹出了一个对话框,

此对话框设置了Top属性,使之能够在所有其它应用程序窗口之上(this->setWindowFlags(windowFlags()|Qt::WindowStaysOnTopHint);)。然后又点击了PushButton,弹出了一子对话框。只见子对话框也自动继承了父窗口的属性,成为了Top window。

在Qt中,我们只需在父窗口设置某些属性(比如Top,bottom),子窗口将自动获得这些属性,使开发者不用为了保持子窗口与父窗口的一致性,每个窗口一个一个去设置。提高了开发效率。

众人皆叹,有父如此,子欲何求。老子干活,儿子享福啊。此时一股浓浓的父爱弥漫在武当大殿中。谁说父爱不顶半边天?此时的男道友们心潮澎湃,激动之余不禁拨通了"流言终结者"的制作组电话。

而反观另外一些道友,眼看她们引以为傲的优势,将被击得荡然无存。她们不甘心失败,一遍遍的看着代码,企图找出一丝破绽来。终于,一位女道友面带冷笑,指着代码说道,“无忌道友,此程序好似有内存泄露,不知对否”。众人心头一紧,Qt往日的无耻又浮现在了人们心头。

但见无忌小友手持羽扇,迎风而立,露出招牌般的正太式微笑,徐徐说道,“早知道友会有此一问。”接着从怀中取出一本写有”九阳真经“的古籍,翻了开来。只见一幅制作精美具有扶桑画风的彩图映入了众人的眼帘,图下面写着”伴我成长的女人们“。张无忌脸色一红,尴尬地咳嗽了一声,又继续翻到了下一页,只见上面写着,

01 QObject::~QObject()
02 {
03 . . . . .
.
04  
05 if (!d->children.isEmpty())
06 d->deleteChildren();
07  
08 . . . . .
.
09 }
10  
11 void QObjectPrivate::deleteChildren()
12 {
13 const bool reallyWasDeleted = wasDeleted;
14 wasDeleted = true;
15 //
delete children objects
16 //
don't use qDeleteAll as the destructor of the child might
17 //
delete siblings
18 for (int i = 0; i <
children.count(); ++i) {
19 currentChildBeingDeleted = children.at(i);
20 children[i] = 0;
21 delete currentChildBeingDeleted;
22 }
23 children.clear();
24 currentChildBeingDeleted = 0;
25 wasDeleted = reallyWasDeleted;
26 }

在Qt中,当以QObject为父类的对象析构时,他会自动删除它所包含的所有子对象,实现了简单的垃圾回收机制,避免了内存泄露。所以开发时可以考虑,每个new出来的对象尽量设置父对象,这样即使未显示调用delete,只要保证父对象被析构,就能避免内存泄露。

武当大殿沸腾了,观众们被Qt父子情深般的精彩表演深深震撼了。”学Qt,得永生“的口号响彻云霄(春哥泪流满面)。《流言终结者》主持人杰米和亚当宣布,人类史上最大的流言"父子不如X子亲"终结了。节目赞助商Intel鉴于此期节目在CCAV上99.99%的收视率,以4.44亿RMB天价强行插入了一条广告“Intel,给Qt一颗奔腾的芯”。

而Qt的代言人无忌小友,获得了道教界一年一度以道家镇教之宝命名的,最高荣誉“八卦”奖。当从道教最高精神领袖“张三丰”手中接过雕有“冠希”前辈手拿camera的小金像,正要发表获奖感言的时侯,一道剑光闪过。

正所谓伯乐不常有,但搅屎棍却常在。

只见人见人怕,鬼见鬼愁,考试只给59分的灭绝师太,手握倚天剑,刷刷的修改了张无忌的代码。

01 class MyTestA : public QObject
02 {
03 Q_OBJECT
04 public:
05 };
06  
07 class MyTestB : public QObject
08 {
09 public:
10 MyTestB(QObject *parent):QObject(parent)
11 {
12  
13 }
14 };
15  
16 extern MyTestB *g_pMyTestB;
17 extern MyTestA *g_pMyTestA;
18 class MyTestC : public QThread
19 {
20 Q_OBJECT
21 public:
22  
23 MyTestC():QThread(NULL)
24 {
25 }
26  
27 void run()
28 {
29 exec();
30 }
31 };
32  
33  
34 MyTestB *g_pMyTestB = NULL;
35 MyTestA *g_pMyTestA = NULL;
36 int main(int argc, char *argv[])
37 {
38 QApplication app(argc, argv);
39  
40 MyTestA
a;
41  
42 MyTestB
b(&a);
43  
44 MyTestC
c;
45 c.start();
46  
47 b.moveToThread(&c);
48  
49 return app.exec();
50 }

执行此段代码后,众人皆惊。只见output窗口输出了“QObject::moveToThread: Cannot move objects with a parent”。

灭绝师太斜眼冷笑道:“黄口小儿,安能善言人伦乎? “

由此可见Qt中,子对象不能脱离父对象,单独切换到与父对象不同的线程中。

此时的张无忌面色惨白。但灭绝师太誓将张无忌搞臭到底,以不负灭绝的美名。只见她又修改了一段代码,

class MyTestA : public QObject
{
Q_OBJECT
public:
};
 
class MyTestB : public QObject
{
public:
MyTestB(QObject *parent):QObject(parent)
{
 
}
};
 
extern MyTestB *g_pMyTestB;
extern MyTestA *g_pMyTestA;
class MyTestC : public QThread
{
Q_OBJECT
public:
 
MyTestC():QThread(NULL)
{
}
 
void run()
{
exec();
}
};
 
MyTestB *g_pMyTestB = NULL;
MyTestA *g_pMyTestA = NULL;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
MyTestA
*pA =
new MyTestA;
 
MyTestB
*pB =
new MyTestB(pA);
 
delete pA;
 
delete pB;
 
 
}

只见程序蹦出了警告对话框,

程序直接崩溃了。与之同时崩溃的,还有众男道友的心。

而张无忌啪跌坐在地上,万念俱灰。与霆锋哥相拥痛哭,为什么上一辈的悲剧,又在我们身上重演。

对于Qt子对象而言,不能在父对象删除后,再删除自己。因为父对象析构时,会删除所有的子对象,此时子对象再删除,会引起二次析构。

所以如果子对象要切换到另一个线程或者避免被父对象删除,则需要调用setParent(NULL),解除父子关系。

灭绝师太仰天长笑道“Qt名为父子,实乃黑帮。”

太史公评曰:“一入Q门深似海,从此萧郎是路人”。

瑟瑟风中,只见张无忌将自己多年的呕心力作<<我与Qt之间不得不说的故事>>付之一炬,飘然而去。从此之后,弃码从武,苦练九阳真经,终成一代大侠,名满江湖,这当然都是后话。

欲知后事如何,请听下回分解。

Qt那点事儿(三) 论父对象与子对象的关系的更多相关文章

  1. OpenCascade拓扑对象之:TopoDS_Shape对象及其子对象

    @font-face { font-family: "Times New Roman" } @font-face { font-family: "宋体" } @ ...

  2. Qt——父对象、布局

    设置父对象两个好处:(1)加入析构树(2)和父对象一起显示 设置布局后,子控件自动被设置父对象 设置父对象两个好处:(1)加入析构树(2)和父对象一起显示

  3. Qt Quick 组件和动态创建的对象具体的解释

    在<Qt Quick 事件处理之信号与槽>一文中介绍自己定义信号时,举了一个简单的样例.定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Co ...

  4. Qt 对象间的父子关系

    C++中只要有一个new就必须要有一个delete与之对应 但是Qt中的对象之间有特殊的关系 Qt 对象间的父子关系 每一个对象都保存有它所有子对象的指针 每一个对象都有一个指向其父对象的指针 par ...

  5. 3dsmax不同版本 pyside qt UI 设置max窗口为父窗口的方法

    3dsmax不同版本 pyside qt widget 设置 max 窗口为父窗口的方法 前言: 3dsmax 在 2014 extension 之后开始集成 Python 和 PySide,但是在版 ...

  6. Qt DLL总结【三】-VS2008+Qt 使用QPluginLoader访问DLL

    目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...

  7. Qt DLL总结【二】-创建及调用QT的 DLL(三篇)good

    目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...

  8. jquery获取元素的值,获取当前对象的父对象等等

    jsp代码: <span><input type="hidden" value="1" id="newInfo">& ...

  9. javascript --- 子对象访问父对象的方式

    在传统面向对象的编程语言里,都会提供一种子类访问父类的特殊语法,引文我们在实现子类方法往往需要父类方法的额外辅助.在这种情况下,子类通常会调用父类中的同名方法,最终以便完成工作. javascript ...

随机推荐

  1. uni-app的H5版使用注意事项

    使用方式 打开uni-app项目下的vue文件 点击菜单 运行->运行到浏览器->Chrome 在Chrome內打开调试模式(右键->检查)开启设备模拟,模拟移动设备(如果UI变形刷 ...

  2. 转载:Web安全 之 X-Frame-Options响应头配置

    转自:https://blog.csdn.net/u013310119/article/details/81064943 项目检测时,安全报告中存在 “X-Frame-Options” 响应头缺失问题 ...

  3. shell脚本——数组

    连续的变量 解决:变量过多的问题,在同一类变量中,不需要定义多个名字,而是以数组的方式来定义 定义数组: declare -I 定义整数 declare -a 定义数组 declare -A 定义嵌套 ...

  4. CentOS系统 Amoeba+MySql主从读写分离配置 适合新手傻瓜式教程!-----仅供参考!

    废话不说,直接开始: 一.安装mysql的三种方式,这里采用第2种(安装方式不再详解,请参照) http://www.cnblogs.com/babywaa/articles/4837946.html ...

  5. Eclipse创建Maven项目时,项目中只存在src/main/resources(没有src/main/java、src/test/java)的解决方法

      例:Maven项目(chapter11),发现只存在src/main/resources,缺少了src/main/java和src/test/java 解决方法: 1.eclipse->wi ...

  6. MPU6050应用

    @2019-08-07 [小记] MPU6050开发 -- 基本概念简介 MPU6050原理详解及实例应用 详解卡尔曼滤波原理 卡尔曼算法精讲与C++实现

  7. nginx解决浏览器跨域问题

    1.跨域问题 浏览器出于安全方面的考虑,只允许与本域下的接口交互.不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源. 例如访问www.test1.com 页面, 返回的文件中需要ajax向 ...

  8. ARM体系结构与编程读书笔记——处理器的寄存器

    ARM处理器共有37个寄存器,其中包括: 31个通用寄存器,包括程序计数器(PC)在内,寄存器都是32位: 6个状态寄存器,这些寄存器都是32位的,目前只使用了其中12位: 通用寄存器 可以分为下面3 ...

  9. wampserver apache 500 Internal Server Error解决办法

    Internal Server ErrorThe server encountered an internal error or misconfiguration and was unable to ...

  10. 浅谈矩阵变换——Matrix

    矩阵变换在图形学上经常用到.基本的常用矩阵变换操作包括平移.缩放.旋转.斜切. 每种变换都对应一个变换矩阵,通过矩阵乘法,可以把多个变换矩阵相乘得到复合变换矩阵. 矩阵乘法不支持交换律,因此不同的变换 ...