本文是GeekBand課程體系中,侯捷老師講課內容的部份內容總結。程序員
參考書籍以下:Effitive C++ 數組
C++ Primer 第五版函數
http://blog.csdn.net/lwbeyond/article/details/6202256 中的部分圖片this
構造函數:如 : String(const char* cstr = 0);spa
拷貝構造函數 如 :String(const String& str);.net
拷貝賦值函數 如 :String& operator=(const String& str);指針
析構函數:如 :~String();code
其中,拷貝構造函數、拷貝賦值函數、析構函數被稱爲C++ 的三大函數!blog
下面以String類進行分析:繼承
1 class String 2 { 3 public: 4 String(const char* cstr = 0); 5 String(const String& str); 6 String& operator=(const String& str); 7 ~String(); 8 char* get_c_str() const { return m_data; } 9 private: 10 char* m_data; 11 };
若是上面定義看起來還不夠直觀,那麼從調用函數角度再看下:
String s2("world"); // 構造函數 String s3(s2); //拷貝構造函數 s3 = s1; // 拷貝賦值函數,左邊的值給右邊,因此稱爲賦值
經過上面的分析,咱們從形式上看到了三種構造函數的區別。固然若是程序員沒寫這些代碼,程序也會自動生成這些代碼~固然自動生成的代碼,有時會有所缺陷。下面
仔細分析下各個地方所須要注意的知識要點。
一、構造函數中不帶指針的狀況
這種狀況比較簡單,只須要賦給參數的初值便可!通常系統自帶生成的構造函數均可以實現。
二、構造函數中若是帶有指針的狀況
以代碼String類爲參考。那麼每次輸入的字符串如何保存呢?可能會想到利用數組,那麼則會碰到另一個問題,那就是數組要多大才合適?
好比說保存「hello」、"helloworld".......字符串的長度每次都不是固定的,這裏能夠採用兩種方法解決!
1、利用動態數組去完成,2、利用指針去完成。相對來講,指針更靈活一些。因此這裏採用指針,並且STL庫裏也是採用指針的方法去完成的
那麼指針是如何肯定字符串大小的呢?
這裏也有兩種方法,一種是指針指向頭部,利用結束符'\0'進行判斷
另外一種第一個字符保存長度大小,後面指針指向實際數據便可。
這裏面採用了 http://blog.csdn.net/lwbeyond/article/details/6202256 中的部分圖片。
原始數據,一個指針指向了數據
淺拷貝:拷貝的只是指針,這種狀況下會出現各類問題!
深拷貝:
若是拷貝構造函數中不含指針的話,那麼編譯器會自動生成拷貝構造函數,既看,只會一位、一位的進行賦值操做。因此此時採用系統默認的狀況便可
但若是拷貝構造函數中含有指針,指針也是4個字節的數據,若是還纔有一位一位的進行賦值,這樣,拷貝過來的指針就會與原指針指向同一個地方。既淺拷貝。
因此若是類中有指針,咱們採用的本身寫的構造函數,這時對應的即是深拷貝!
1 inline 2 String::String(const String& str) 3 { 4 m_data = new char[strlen(str.m_data) + 1]; 5 strcpy(m_data, str.m_data); 6 }
這裏採用String (const String &str),說明它只接受 「它本身這樣的東西」 因此咱們採用new 先建立一個空間大小能夠保持複製過來的數據
而後再賦給數據便可
(PS:new 這裏面也是採用malloc 進行開闢空間的)
首先觀察下String類的拷貝賦值函數
1 inline 2 String& String::operator=(const String& str) 3 { 4 if (this == &str) 5 return *this; 6 7 delete[] m_data; 8 m_data = new char[strlen(str.m_data) + 1]; 9 strcpy(m_data, str.m_data); 10 return *this; 11 }
經過觀察 把S2 = S1,實際上就是完成操做符重載的過程(operator+)以下:
一、先刪除S2本身自己的內存;
二、而後從新分配一塊與S1大小相同的內存;
三、再把S1的內容拷貝到S2上便可。
~~滿滿的都是套路~~
那麼判斷 this 與&str 是什麼東西?爲何要這麼作?
簡單的思考就是,節省效率嗎,單並非主要緣由,下面採用侯捷老師課程中的資料解釋下:清晰明瞭!
inline String::~String() { delete[] m_data; }
通常來講,會隱式的自動調用析構函數,因此不少狀況下沒必要寫出來。
然而,若是有指針,仍是要自動進行釋放掉,不然會引發內存泄露等問題。
析構函數中還對應着繼承、委託等各類狀況下的析構順序等,這些留着下篇進行分享。
————以上這些均來自GeekBand,侯捷老師授課內容。侯捷老師具備豐富的C++知識,聽課後收穫很大。
By NiceCoder