在面向对象的程序设计中,类是一种事物的抽象,它并不是实物,故本文其实描述的应该是一个类的对象如何实现自杀;之所以提升到类的高度,是因为实现自杀的函数(方法)是要由类来提供的,而且该类的所有对象都是利用这样的方法自杀的。
为什么要实现类的自杀?一个类对象要结束自己的生命时,可以直接由创建该对象(例如:new)的主人杀死它(例如:detele)就行了嘛!说的没错,大多数情况下的确是这样的,但凡事总有例外嘛。
下面我们首先分析一下一个类对象究竟何时死掉吧!我们把想死的类对象称为A,另外一个类对象称为B。
【情况1】:
A是类B的成员变量。此时B就是A的主人了,主人B在自己死掉(析构)之前会将A杀死,这种情况下A成了B的陪葬品,谁叫B是自己的主子呢!
【情况2】:
A是在B的某个函数中临时创建出来的对象。当函数结束后,A的生命就自然终结了,其实是被系统杀死了。此时的A只是这部程序剧本中的一个小小的过客。
【情况3】:
A是在某个特殊的时候某个地方被B通过new的方法创建的,这时会有一把枪一直指向它。这把对准它的枪可能被B持有,也可能被B转给了C或者D持有,只要任何人拿枪指向了它,它就得乖乖听话,听从指挥。
这时,A的生命何时终结完全得看持枪对准它的人的心情了,只要人家一不高兴,随时都可以通过delete把它毙掉。当然,若持枪对准它的人在死的时候都忘记杀死它或者大家的枪都指向了其他地方的话,它便成为了一块被泄露的内存,一直没有机会死去。
【情况4】:
A是全局的静态对象。这时它的生死不是其他人可以左右的,它有着极长的寿命,随着整个程序的启动而诞生,随着整个程序的结束而死亡。它会在整个程序即将结束前,在其他的非静态类或者变量都死去之后,与各位静态对象们一起光荣地被系统杀掉。
【情况5】:
可能A还有其他的死法,这里我就不一一列举了。
下面我们切入正题,讨论一下类的自杀行为。通过以上几种情况我们可以看出,对象A的死都不是自愿的,都是由系统或者主人强行杀死它的,那么,究竟什么情况下会出现A自己想死呢?
【情况1】:
类A是一个任务执行者,该任务的特点是: 当任务执行完毕后,A必须自杀或者通知上级把自己杀死。
例如:A为视频播放执行者类,当上级创建出A类的对象,并告知A需要播放的资源的必要信息后,A即启动对该视频资源的播放,由于播放是否结束只有底层A才知道,上级是不可能第一时间知道播放已经结束的,这时播放资源该如何正常释放呢?上级如何才能知道何时把A对象干掉呢?
这时有两种途径:
(1) 由A自行了断,即自杀,不需要上级再操心,这种情况上级还是挺满意的,很省事。
(2) 由A通过某种方式告诉上级:"播放完毕,可以把我干掉了。" 虽然还得让上级操心,不过上级处理起来也容器,一刀干掉A就行了。
【情况2】:
类A身负国恨家仇,当上级要它死时,它不能立即死掉,而是要继续完成最后的使命后,再自行了断。
例如:A为某网络传输的发送者,它的任务是将上级交给它的东西发送到网络接收端B。具体过程是这样的:上级每次都把需要传输给B的东西塞到了A的缓冲区中,A只需不断地定时从缓冲区取出一定量的数据,然后发送到B即可。
传输一段时间后,上级发现需要传递到B的东西已经全部塞给A了,于是命令A:“你自杀吧!”;(设置A的自杀变量为true)。这时A发现自己缓冲区的东西还没有传输完毕呢,于是回答上级:“哦,好的,一会我会自杀的”,于是,当A将缓冲区的东西全部传输完毕后,便自杀了。
这种情况与上面情况1极为相似,但情况还是略有不同的,可能我举得例子不够典型,读者可以自己尝试创建一个更加典型的例子。
【情况3】:
类A执行任务的过程中遇到了重大的问题(异常),需要通知上级干掉自己以保证程序正常运行或者资源的正常释放。
例如:还是举网络发送者的例子吧,例如A为某网络传输的发送者,任务依然是向指定目的地址B发送数据。本来这份工作也挺简单的,但偏偏老天捉弄人,网络出现了一些问题,导致发送数据时出现一些异常。这时A敏锐地觉察到了网络的异常情况,这样继续发送数据到B,可能会导致B接收到一些错误的数据,很可能发生一些意想不到的异常,因此,A必须停止数据的发送。这时,A有两种选择:(1) 苟且偷生。它大可关闭网络发送的连接,并且将发送缓冲区中的数据扔掉,应该能够保证程序的平安无事,只是上级很是奇怪,为什么最近B经常告诉自己为什么没有发东西过去了?(2)通知上级杀掉自己。A经过仔细权衡,此次异常问题重大,必须立即通知上级干掉自己,以保证资源的正常释放,以及后续工作的正常运作。
当然,这种情况下的自杀想法一定是发生了重大异常,必须通过干掉自己才能够保证后续工作的情况下,A才会产生自杀的想法的。
【小结】:
我们知道,到达目的地的路径往往不只一条。上面描述的各种情况其实也都很相似,并且是可以不必使用自杀策略实现最终的目的,比如说:上级开辟一个线程,定时不断地去询问A的状态,一旦发现A完成任务了可以死了或者说A遇到异常了想死了,马上将A杀死即可。我们本文讨论的自杀行为只是达到目的的另外一条路径而已。
这里我们需要注意,我们说的自杀,主要指的是想自杀,实现这样的想法有两种途径,第一种是自己把自己杀死,即“自行了断”;另外一种是通过通知其他人,达到让人家把自己杀掉的目的,即“借刀杀己”。
下面我们将讨论一下A到底有哪些办法实现上面描述的自杀行为?
【方法1:发送消息】:
这种方法有一定的局限性,它只能用于MFC的框架下,因为MFC实现了消息机制,我们可以利用该消息机制将底层的自杀想法传达到上级,再由上级杀死自己即可。
具体用法见MFC的PostMessage和SendMessage两个函数。
本方法属于“借刀杀己”。
【方法2:回调】:
由外界使用者注册一个回调函数到本类中,当本类对象想自杀时,可以通过调用该回调函数通知到外界,外界可以在该回调函数中执行杀死该对象的代码。
回调是非MFC下实现通知机制的有效途径,这种方法其实也属于“借刀杀己”。
【方法3:开线程把自己干掉】:
这是一种高级的死法,真正实现了“自行了断”,不需要外界操心。在类对象产生了“自杀”的想法后,可以立即开启一个线程,将this指针传递过去,在该线程中执行杀死该类对象的代码,终结该对象的生命。
使用这种方式需要注意一个问题,那就是外界是不知道你已经死了,所有一定要防止外界在你死后依然使用你,故为了安全起见,自行了断前或者了断后还是需要通过某种方式告知一下外界的。
【方法4:垃圾回收机制 】:
之所以取这个名字,是因为它的确有点像垃圾回收。我们可以专门有一个线程,线程中会不断地扫描垃圾回收站(或许是某个静态单件类)中是否有需要清理的垃圾,若有,则无情地挥舞大刀干掉这些回收站中的垃圾;于是,当一个类对象想“自杀”时,便通过垃圾回收站提供的接口把自己扔到垃圾回收站中,静静地排队等待被无情地杀死。
同样,这也是一种“自行了断”的方式,同样需要注意与【方法3】同样的问题。
原文转自: 乐搏学院http://www.learnbo.com/front/article/cmsIndexs