劍指Offer讀書筆記(持續更新中)

乞力馬紮羅的雪CYF發表於2015-08-23

(1)定義一個空的型別,裡面沒有任何成員變數和成員函式,對該型別求sizeof,得到的結果是多少?

答案是1。空型別的例項中不包含任何資訊,本來求sizeof應該是0,但是當我們宣告該型別例項的時候,它必須在記憶體中佔有一定的空間,否則無法使用這些例項。至於佔用多少記憶體,由編譯器決定。Visual Studio中每個空型別的例項佔用1位元組的空間。


如果在該型別中新增一個建構函式和解構函式,再對該型別求sizeof,得到的結果又是多少?

答案還是1。呼叫建構函式和解構函式只需要知道函式的地址即可,而這些函式的地址只與型別相關,而與型別的例項無關,編譯器也不會因為這兩個函式而在例項內新增任何額外的資訊。


如果把上述的解構函式標記為虛擬函式,情況會怎樣?

C++編譯器一旦發現一個型別中有虛擬函式,就會為該型別生成虛擬函式表,並在該型別的每一個例項中新增一個指向虛擬函式表的指標,在32位的機器上,一個指標佔4位元組的空間,因此求sizeof得到4,如果是64位的機器,一個指標佔8位元組的空間,因此求sizeof得到8.


(2)看C++程式,判斷結果:

#include <iostream>

class A{

private:
    int value;
    
public:
    A(int n){
    
        value = n;
    }
    
    A(A other){
    
        value = other.value;
    }
    
    void Print(){
    
        std::cout<<value<<std::endl;
    }
};

int main(int argc, const char * argv[]) {

    A a = 10;
    A b = a;
    b.Print();
    
    return 0;
}

選擇A.編譯錯誤       B.編譯成功,執行時程式崩潰             C.編譯執行正常,輸出10


答案是A,編譯出錯。

我把程式放到IDE中,報錯行數和提示如下:

錯誤提示是說複製建構函式傳遞的第一個引數必須是引用型別。在上述程式碼中,複製建構函式A(A other)傳入的引數是A的一個例項。由於是傳值引數,我們把形參複製到實參會呼叫複製建構函式。因此如果允許複製建構函式傳值,就會在複製建構函式內呼叫複製建構函式,就會形成永無休止惡遞迴呼叫從而導致棧溢位。因此C++標準不允許複製建構函式傳值引數。在Visual Studio和GCC中,都會編譯出錯。要解決這個問題,就是把傳值引數修改為常量引用。程式碼如下:

A(A const &other){
    
        value = other.value;
    }

(3)題目:如下為型別CMyString的宣告,請為該型別新增賦值運算子函式。

class CMyString{

public:
    CMyString(char* pData = NUll);
    CMyString(const CMyString& str);
    ~CMyString(void);
    
private:
    char* m_pData;

    
};

解決該問題應該首先注意以下幾點:

         1.是否把返回值的型別宣告為該型別的引用,並在函式結束前返回例項自身的引用(即*this)。只有返回一個引用,才可以允許連續賦值。否則如果函式的返回值是void,應用該賦值物件符將不能做連續賦值。假設有三個CMyString物件,str1,str2,str3,在程式中語句str1=str2=str3將不能通過編譯。

        2.是否把傳入的引數的型別宣告為常量引用。如果傳入的引數不是引用而是例項,那麼從形參到實參會呼叫一次複製建構函式。把引數宣告為引用可以避免這樣的無謂的消耗,能提高程式碼的效率。同時,我們在賦值運算子函式內不會改變傳入的例項的狀態,因此應該為傳入的引用引數加上const關鍵字。

        3.是否釋放例項自身已有的記憶體。如果我們忘記在分配新記憶體之前釋放自身已有的空間,程式將出現記憶體洩露。

        4.是否判斷傳入的引數和當前的例項(*this)是不是同一個例項。如果是同一個,則不進行賦值操作,直接返回。如果事先不判斷就進行賦值,那麼在釋放例項自身的記憶體的時候就會導致嚴重的問題:當*this和傳入的引數是同一個例項時,那麼一旦釋放了自身的記憶體,傳入的引數的記憶體也同時被釋放了,因此再也找不到需要賦值的內容了。


實現程式碼如下:

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

  if(this == &str){
  
    return *this;
    
  }
  
  delete []m_pData;
  m_pData = NULL;
  m_pData = new char[strlen(str.m_pData) + 1];
  strcpy(m_pData,str.m_pData);
  
  return *this;
}

(4)C++中可以使用struct和class來定義型別,這兩種型別有什麼區別?

如果沒有標明成員函式或者成員變數的訪問許可權級別,在struct中預設是public,在class中預設是private。


github主頁:https://github.com/chenyufeng1991  。歡迎大家訪問!












相關文章