Qt那点事儿(三) 论父对象与子对象的关系

原文地址::http://www.cnblogs.com/andreitang/archive/2011/08/25/2128508.html


相关文章

1、Qt那点事儿(一)----http://www.cnblogs.com/andreitang/archive/2011/08/03/2125815.html

2、Qt那点事儿(二)----http://www.cnblogs.com/andreitang/archive/2011/08/08/2128505.html


第三回 父与子

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <QDebug>
#include <QThread>
 
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();
     }
};
int  main( int  argc,  char  *argv[])
{
     QApplication app(argc, argv);
 
     MyTestA a;
 
     MyTestB b(&a);
 
     MyTestC c;
     c.start();
 
     a.moveToThread(&c);
     if (a. thread () == b. thread () && a. thread ()!=app. thread ())
     {
         qDebug()<<  "Both parent and son have the same thread" ;
     }
 
     return  app.exec();
}

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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()
     {
         g_pMyTestA->moveToThread( this );
         exec();
     }
};
 
MyTestB *g_pMyTestB = NULL;
MyTestA *g_pMyTestA = NULL;
int  main( int  argc,  char  *argv[])
{
     QApplication app(argc, argv);
 
     MyTestA a;
     g_pMyTestA = &a;
 
     MyTestB b(&a);
 
     MyTestC c;
     c.start();
 
     return  app.exec();
}

却见output窗口打出,

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <QThread>
 
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(QObject *parent):QThread(parent)
     {
     }
};
 
 
class  MyTest :  public  QDialog
{
     Q_OBJECT
 
public :
     MyTest(QWidget *parent = 0, Qt::WFlags flags = 0);
     ~MyTest();
 
protected  slots:
     void  onClick();
 
 
private :
     Ui::MyTestClass ui;
};
/
MyTest::MyTest(QWidget *parent, Qt::WFlags flags)
     : QDialog(parent, flags)
{
     ui.setupUi( this );
     //set the window to be the top window
     <span style= "color: #ff0000;" > this ->setWindowFlags(windowFlags()|Qt::WindowStaysOnTopHint);</span>
}
 
MyTest::~MyTest()
{
 
}
 
void  MyTest::onClick()
{
     <span style= "color: #ff0000;" >QMessageBox box( this );</span>
     box.setText( "i am at the top" );
     box.exec();
}
 
//main.cpp///
MyTestB *g_pMyTestB = NULL;
MyTestA *g_pMyTestA = NULL;
int  main( int  argc,  char  *argv[])
{
     QApplication app(argc, argv);
 
 
 
     MyTestA a;
 
     <span style= "color: #ff0000;" >MyTestB *pB =  new  MyTestB(&a);</span>
    <span style= "color: #ff0000;" > pB->setObjectName( "MyTestB" );</span>
 
    <span style= "color: #ff0000;" > MyTestC *pC =  new  MyTestC(&a);</span>
     <span style= "color: #ff0000;" >pC->setObjectName( "MyTestC" );</span>
 
     <span style= "color: #ff0000;" >pC =  new  MyTestC(&a);</span>
     <span style= "color: #ff0000;" >pC->setObjectName( "MyTestC1" );</span>
 
     <span style= "color: #ff0000;" >QList<QObject*> list = a.findChildren<QObject*>();</span>
     QList<QObject*>::iterator it;
     qDebug()<< "All the son list: " << "\r\n" ;
     for (it = list.begin(); it != list.end() ; it++)
     {
         qDebug()<<(*it)->objectName()<< "\r\n" ;
     }
     qDebug()<< "============================" << "\r\n" ;
 
 
     <span style= "color: #ff0000;" >QList<MyTestC*> listC = a.findChildren<MyTestC*>();</span>
     QList<MyTestC*>::iterator itC;
     qDebug()<< "MyTestC list: " << "\r\n" ;
     for (itC = listC.begin(); itC != listC.end() ; itC++)
     {
         qDebug()<<(*itC)->objectName()<< "\r\n" ;
     }
     qDebug()<< "============================" << "\r\n" ;
 
    <span style= "color: #ff0000;" > MyTestC *pC1 = a.findChild<MyTestC*>( "MyTestC1" );</span>
     if (pC1)
     {
         qDebug()<< "MyTestC1 has been found" << "\r\n" ;
     }
 
     MyTest win;
     win.show();
 
     return  app.exec();
}

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

在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往日的无耻又浮现在了人们心头。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
QObject::~QObject()
{
    . . . . . .
 
     if  (!d->children.isEmpty())
         d->deleteChildren();
   
    . . . . . .
}
 
void  QObjectPrivate::deleteChildren()
{
     const  bool  reallyWasDeleted = wasDeleted;
     wasDeleted =  true ;
     // delete children objects
     // don't use qDeleteAll as the destructor of the child might
     // delete siblings
     for  ( int  i = 0; i < children.count(); ++i) {
         currentChildBeingDeleted = children.at(i);
         children[i] = 0;
         delete  currentChildBeingDeleted;
     }
     children.clear();
     currentChildBeingDeleted = 0;
     wasDeleted = reallyWasDeleted;
}
  

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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 a;
 
     MyTestB b(&a);
 
     MyTestC c;
     c.start();
 
     b.moveToThread(&c);
   
     return  app.exec();
}

执行此段代码后,众人皆惊。只见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之间不得不说的故事>>付之一炬,飘然而去。从此之后,弃码从武,苦练九阳真经,终成一代大侠,名满江湖,这当然都是后话。

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


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值