《劍指Offer》面試題1:賦值運算符函數


《劍指Offer——名企面試官精講典型編程題》

作者:何海濤


一、書上原題再現

面試題1:賦值運算符函數

題目:如下為類型CMyString的聲明,請為該類型添加賦值運算符函數。

class CMyString

{

public:

    CMyString(char* pData = nullptr);

    CMyString(const CMyString& str);

    ~CMyString(void);

 

    void Print();

     

private:

    char* m_pData;

};


二、涉及的知識點

 

                         


三、解題過程

賦值:

       int a;  //聲明

       a = 10; //賦值

      

運算符:

       + - * / = % < > ?: 等等

      

賦值運算符:

       =

      

賦值運算符函數:

       What?嗯?

 

其實,這里涉及到了運算符重載的知識點。我一個遨游在Java大海里的浪子,突然灌一口C/C++的海水,感覺有點生澀。

 

什么是運算符重載?

簡單講,比如說:

       + 加號的本意是   1+1 = 2  在這里是 累加 的功能

       在類似於Java、Python這類高級語言中,當 + 加號 出現在字符串之間比如 "Hello" + "World !",那么這里的加號就會被用來實現 連接兩個字符串 的功能。

       加號不干 累加 的功能,而是實現了 連接兩個字符串 的功能,這就叫做 加法運算符的重載。

       運算符重載中有一點要求需要特別注意:重載運算符的參數至少應有一個是類對象(或類對象的引用)

  也就是說,參數不能全部是C++的基本類型,以防止用戶修改用於基本類型數據成員的運算符的性質,如下面這樣是不對的:

                     int operator + (int a,int b)

                     {

                            return(a-b);

                     }

  原來運算符+的作用是對兩個數相加,現在企圖通過重載使它的作用改為兩個數相減。

  如果允許這樣重載的話,那么表達式4+3,它的結果是7還是1呢?顯然,這是絕對要禁止的。

             

Java八大基本數據類型:

              byte   short        int          long

              float   double     boolean         char

      

       基本數據類型是沒有String的,String的本質是一個用戶類。所以說當加號出現在兩個字符串之間的時候,實現連接兩個字符串這個功能是加法運算符的重載。

       但是,但是,但是,Java語言沒有運算符重載:

              Java doesn’t support user-defined operator overloading.

                Java不支持用戶自定義操作符重載。

              The preferred approach is to define a method on your class to perform the action: a.add(b) instead of a + b.

                首選的方法是在類中定義一個方法來實現這個功能,比如說通過 a.add(b) 來實現 a+b 的功能。

              The only aspect of Java which comes close to “custom” operator overloading is the handling of + for strings,

                Java唯一接近“自定義”運算符重載的方面是 + 用於字符串的處理,

              which either results in compile-time concatenation of constants or execution-time concatenation using StringBuilder/StringBuffer.

                這里的加法會造成在編譯期或執行期使用StringBuilder/StringBuffer。

             

       那么回到正題,這道題用的語言是C++,C++是有運算符重載的,給一個類添加賦值運算符函數。這個類就是一個字符串類,名為:CMyString

賦值運算符函數,就是重載賦值運算符了。下面是該函數的聲明:

       CMyString& operator = (const CMyString& str);

       CMyString& 是函數的類型   operator = 整體看成函數名 const CMyString&是參數的類型 str 是參數的引用名

       我們要做的就是書寫函數體。

初級程序員版:

1     CMyString& operator = (const CMyString& str){

2            if(this == &str){

3                   return *this;

4            }else{

5                   delete []m_pData;

6                   m_pData = NULL;

7                   m_pData = new char[strlen(str.m_pData)+];

8                   strcpy(m_pData, str.m_pData);

9                   return *this;

10          }

11   }

       這一版本的Bug之處就在於,假如第5、6行代碼執行完成之后,第7行代碼在分配內存的時候,分配失敗了,那么我原先的數據也就沒有了。

這樣原先的對象就會成為一個空指針,想象一下,一個空指針在程序中,一旦程序后文又用到這個對象,那么這個程序極有可能崩潰!!!

考慮到異常安全性,下面的代碼是

高級程序員版:

1     CMyString& operator = (const CMyString& str){

2            if(this == &str){

3                   return *this;

4            }else{

5                   CMyString strTemp(str);

6                   char* pTemp = strTemp.m_pData;

7                   strTemp.m_pData = m_pData;

8                   m_pData = pTemp;

9                   return *this;

10          }

11   }     

 


四、調試步驟

使用DevC++進行調試

 

 


五、總結

不理解的地方:

                 CMyString strTemp(str);  看不懂這句代碼,這句代碼怎么就創建一個臨時對象了,

這難道不是 類型名   函數名  參數?如果是這樣的話,那么這個函數連聲明都沒有直接就用了?

       既然臨時對象一但運行結束就會被析構,那么為什么要進行交換?直接把臨時對象的值賦值給當前對象的值不就行了?

       一行代碼

              m_pData = strTemp.m_pData

       不比三行代碼強嗎?

  如果是說不能這樣直接進行賦值,需要有個 char* pTemp的中間變量,那也應該是

  兩行代碼:

              char* pTemp = strTemp.m_pData;

//            strTemp.m_pData = m_pData;

              m_pData = pTemp;

  中間那行代碼的意義何在,難不成是寫交換算法寫順手了???

             

  百思不得其......(所以我現在還不是高級程序員......)             

             

總結:

  1、 C++中通過運算符函數(關鍵字operator)可以對運算符進行重載;

  2、如果要為一個類寫賦值運算符函數,需要考慮內存分配失敗的異常情況下要原對象不能為空指針的情況;

  3、 一個對象的值,可以在創建的時候通過構造函數進行賦值,

    也可以把另一個對象的值通過賦值運算符賦值給當前對象,

    也可以通過賦值運算符進行多個對象的連續賦值,

    這,就是賦值運算符函數的意義;

  4、C++很飄逸,很成功,很失敗,臨時對象很難懂;

  5、這道題的精髓我認為是就兩點:

    一是如何把這個operator = 函數完整的寫出來,

    二是在寫的過程需要考慮內存泄漏的情況。

 


六、聲明與致謝

本題源代碼請移步《劍指Offer》作者何海濤的GitHub:https://github.com/zhedahht/CodingInterviewChinese2/blob/master/01_AssignmentOperator/AssignmentOperator.cpp

      

參考文章:(每篇文章我都會去點贊,好的文章就應該公諸於世,大家共同學習)

  博客園:

    顏之年《C++重載運算符的規則詳解》:https://www.cnblogs.com/summernight/p/8541079.html

    同勉共進《一文說盡C++賦值運算符重載函數(operator=)》:https://www.cnblogs.com/zpcdbky/p/5027481.html#top

    默默淡然《運算符重載詳解》:https://www.cnblogs.com/liangxiaofeng/p/4311796.html

  RUNOOB:

    Java基本數據類型:http://www.runoob.com/java/java-basic-datatypes.html

  CSDN:

    michellechouu《【C++】賦值運算符函數》:https://blog.csdn.net/michellechouu/article/details/47298445

    liaotl10《才知道java竟然沒有運算符重載》:https://blog.csdn.net/liaotl10/article/details/74999757

    Do丶YouMissing《java中是否對“+”,“=”,“+=”重載》:https://blog.csdn.net/caonima0001112/article/details/50492718

    viclee108《淺析Python運算符重載》:https://blog.csdn.net/goodlixueyong/article/details/52589979

  技術小黑屋:https://droidyue.com/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM