Jecho

导航

深切解析各类办法实现两个变量的互换

http://www.cesclub.com/bw/jishuzhongxin/bianchengyuyan/2011/0810/2739.html

 

小我若是但靠本身,若是置身于集体的关系之外,置身于任何连合公众的巨大思惟的局限之外,就会变成懈怠的、保守的、与生活生计成长相敌对的人。 本篇择要

世界上最讨人厌的一种活就是失败者的来由   互换两个变量是很是古老的话题了,然而本文绝对包管给你新鲜的感触感染!本文涉及到最简单的“不消姑且变量互换两个整数”还涉及到若是哄骗异或来实现两个指针、两个浮点数的互换,要知道指针的浮点数是不容许直接异或运算的哦;同时本文还论说了如何互换用户自定义类型及其指针。

本文美满是小我阐扬之作,迎接广大砖家来拍砖,我小我感触感染文中必定有很多不足,甚至错误之处,这并非我礼让,事实上我写本文的目标就是在挨砖板中成长!新人或许看不懂很多器材,若是你看不懂,那么就不要随便跪拜,因为看不懂的或许底本就是错的,高手看完后若是本文写得还可以,那么请留下好评,以供新手参考本文是否有浏览本文的须要,若是感觉本文美满是垃圾,那么请不要客套,您可以地,露骨地指出本文的错误和不足,让本人在批驳中进步,但请不要进行人身进击,感谢!

筹办工作

  因为本文涉及到互换两个用户自定义类型的变量,为了举例便利,本订婚义如下的Person类(此中省略了拷贝机关函数的重写,因为本文不消到它):

 

 

  为了后文表述便利,这里再定义Person类的两个对象和两个指针,定义如下:

 

 

最常见的互换两个对象的办法:GeneralSwap

   凡是,我们为了互换两个变量都采取下面的办法来实现,它须要一个姑且变量:

 

 

   显然人人都知道这个写法,然则我仍然感觉有须要重点申明几点:1、重视函数的参数是引用(也可指针),为什么我就不说了然;2、这个互换函数根蒂根基上是最简单、最通用的,简单到人人都邑写,通用到它几乎可实用于任何数据类型:char ,int , long , float, double等各类体系自定义数学类型(无符号的,带符号的),用户自定义数据类型(须要有默认机关函数,不然语句T temp;会报错),以及各类指针(体系自定义类型的指针,和用户自定义类型的指针)。当然用户自定义类型中若是包含了指针数据成员,那么须要重载赋值运算符,事实上如许的用户自定义类,你都应当本身重写赋值运算符、拷贝机关函数,不然不单不克不及应用GeneralSwap,其他涉及到拷贝和赋值的操纵都可能导致失足!

哄骗GeneralSwap互换两个用户自定义对象

  下面深切商量一下关于用户自定义对象的互换题目:针对筹办工作中的Person类的两个对象youngMan和oldMan语句GeneralSwap(youngMan,oldMan);能实现他们的互换。短短一行代码就能实现将一个18岁的花季少男跟一个81岁的老头子掉包,这像不像是耍魔术啊,呵呵。要重视了,该互换代码虽短,但涉及到默认机关函数的调用(GeneralSwap中的T temp;语句)和赋值运算符重载函数的调用(GeneralSwap中的三个赋值语句)。

或许您很少这么用吧,事实上在我写本文之前,我都没真正互换过两个自定义的对象,凡是我们都不肯意这么互换两个自定义对象。原因是效力太低!或许你要问,万一有的应用就是须要互换两个自定义的对象怎么办?好办,用指针啊!对,指针的益处就是效力高,为什么C++比java效力高,原因之一就是java作废了指针。下面的第一行代码就是互换两个Person类的指针:

 

 

  为什么应用指针就效力高了呢?原因是指针就是地址,地址就是整数,于是题目等价于互换两个整数,是以它不调用赋值运算符重载函数!只要你在应用法度中始终经由过程指向对象的指针来接见对象,那么互换两个指针就能达到互换对象的目标。重视被注释掉的第二行代码,它是正确的,然则它又回到了互换两个实际对象,其效力低,最好不要这么用!

   对于这个最常见、最简单的GeneralSwap我都空话了一大堆,并且还扯出了一个没几许用的关于用户自定义对象的互换题目,这实属小我思维散射,请砖家们狠狠地拍。

在进行下一个办法之前,再次夸大一点,这个办法的特点是简单、通用!后面的办法都将与之做斗劲。

哄骗加减法实现两个数的互换

   几乎人人都知道还可以哄骗加减法来实现两个数的互换,其代码也异常简单:

 

 

  Add_Sub_Swap_1可以用于互换两个整数,但因为涉及加减法,是以稀有据溢出的危险;也可以用于互换浮点数,然则有可能因为舍入误差导致成果不正确。

  Add_Sub_Swap_1不克不及用于互换两个用户自定义的对象,下面的语句编译就经由过程不,编译器告诉你Person类没有定义operator +等符号:

Add_Sub_Swap_1(youngMan,oldMan);//编译通不过!

  Add_Sub_Swap_1不克不及用于互换两个指针,语句Add_Sub_Swap_1(pYoungMan,pOldMan);编译时将报错:error C2110:cannot add two pointers,是的,两个指针不克不及直接做加法运算(减法是可以的)。那么是不是就不克不及哄骗加减法实现两个指针的互换呢?答案是:“可以!”,接下来我将论说如何实现。

哄骗加减法互换两个指针

  Add_Sub_Swap_1不克不及用于互换两个指针,前面我说可以用加减法来实现两个指针的互换,这是有按照的:指针仍然是变量,只不过它是存储通俗变量的地址的变量。只要我们把指针“看作”变量,那么就能实现加法。那么如何把指针“看作”变量呢?答案是:“经由过程强迫类型转换”!指针默示变量的地址,在32位平台上它是一个无符号的整数,是以可以将指针强迫转换为无符号类型的整数。我对上方的Add_Sub_Swap_1进行了改进:

 

 

  哄骗Add_Sub_Swap_2既可以互换两个通俗的整数、浮点数同时它可以互换两个随便率性类型的指针(包含体系预定义类型和用户自定义类型的指针,其实本质上所有指针都属于同一种类型:32位无符号整数类型)。不信您尝尝Add_Sub_Swap_2(pYoungMan,pOldMan);它能获得正确答案。

  固然Add_Sub_Swap_2解决了Add_Sub_Swap_1无法互换两个指针的题目,然则它仍然无法互换两个用户自定义类型的变量,原因是用户自定义类型没有加减法运算。看来要想用加减法实现两个用户定义类型的互换是不成能的了(除非用户自定义的operator+和operator-能满足互换两个对象的目标,这很难,除非是很是简单的用户自定义类型,比如你不应用体系类型int非要定义一个MyInt类)。

哄骗异或实现两个整数的互换

同样地,几乎人人都知道哄骗异或来互换两个数,其实现也很是简单:

 

 

  上方的函数的实用性很是有限,它只能互换两个整数(包含char,int,long),要想互换两个浮点数是不可的,因为浮点数不克不及参与位运算,要想互换两个指针也是不可的,编译器不容许你把两个指针拿来做位运算,要想互换两个用户自定义对象也是不可的,因为它仍然不克不及参与位运算。那么是不是哄骗异或互换两个变量就没法用于浮点数、指针和用户自定义的对象了呢?答案是“能”!后面几节我将论说这些题目。

哄骗异或实现两个float和指针的互换

  前面的Xor_Swap_1无法实现两个浮点数和指针的互换,其原因是浮点数和指针均不直接支撑位运算。那么如何才干哄骗异或来互换两个浮点数和指针呢?办法仍然是“强迫类型转换”!因为浮点数在内存中仍然是用一串二进制bit来默示的嘛,只要把浮点数看作(强迫类型转换)二进制bit构成的整数,那么就能进行位运算了,至于指针嘛,处理惩罚办法完全雷同。具体如何做呢,其实现可能是如许的:

 

 

    哄骗这个函数可以互换两个float类型的变量,也可以互换随便率性类型的指针!很是值得重视的是:用它互换两个double类型数据或者两个Person类的对象(youngMan,oldMan)均能编译经由过程,然则其成果倒是错的。至于为什么,以及如何解决,这将是我下一节要论说的内容。

哄骗异或实现两个double类型变量和用户自定义变量的互换

   Xor_Swap_2解决了哄骗异或不克不及互换两个float数据和指针的题目,然而它却不克不及正确地互换两个double数据和两个Person类对象。这是为什么呢?原因是函数内部是把参数强迫类型转换成unsigned类型的,而sizeof(float)和sizeof(pointor)的值都便是sizeof(unsigned),然则sizeof(double)却不便是sizeof(unsigned),也就是说把double强迫转换成unsigned类型时,产生了“位截断”(在概念是差别与数据截断),那么获得的成果必然就不合错误了。至于无法互换两个Person类对象,其原因也雷同。

  这里我要深切解析一下强迫类型转换是如何产生位截断的,起首看看以下测试的输出成果,重视代码中的注释,为了节俭篇幅,我把值得重视的处所都放在注释中了:

 

 

   可以看出两个double数据并没被互换,而两个Person对象在互换之后产生了怪异现象:产生了81岁的年青人和18岁的老年人!这一点正好申明强迫类型转换时产生了位截断,因为Person类的第一个数据成员m_Age正好是int型,在Xor_Swap_2内部做强迫类型转换时正好取得了两个对象的m_Age成员,于是呈现了两个对象被项目组互换的景象,那么又如何申明两个double数据没有变法呢?事实上两个double数据仍然产生了项目组互换,因为这里的两个double数(a,b)的前4个字节正好雷同,是以看不出项目组互换。

既然我们知道了Xor_Swap_2为什么不克不及用于互换两个double类型的数据和两个用户自定义的数据,那么就有办法对它进行改进。具体改进的思惟就是把参数遵守一个byte一个byte地分别异或,遵守这个思路我实现了如下的函数:

 

 

    这个版本的函数不仅能互换两个整数、任何指针、float数和double数,更牛逼的是它能互换两个用户定义类型的变量!事实上它根蒂根基上是在内存一级上操纵数据,而任何类型的数据对象终极都发挥解析为内存对象。这其实就是经由过程内存拷贝实现两个对象的互换的一个版本吧,当然还有哄骗memcpy等手段进行内存拷贝来实现两个变量的互换的,这里我就不赘述了。

停止语

    本篇到此写完了,有种不好的感触感染,因为文中多量应用“强迫类型转换”而这个器材是C++中轻易失足的处所,而我再写本文时,并没有去复习关于强迫类型转换的相干常识,是以愁闷很多处所有潜伏的失足可能,还请各位砖家斧正!

posted on 2013-05-07 20:18  Jecho  阅读(438)  评论(0编辑  收藏  举报