最近在找工作,比較忙,所以沒有時間寫文章了。找了一段時間了,還是沒有什麼收穫。找工作給我乙個最大的體會就是"基礎要紮實,**能力要強(這裡的**不是指那種業務邏輯的**哦)"。01 文章概要這篇文章總結一下c++中的建構函式,然後自己實現乙個mystring類,實現對mystring字串的輸入和輸出。如果對c++熟悉的童鞋應該就能猜到後面要介紹的知識了:
介紹的過程中,不會對所有的都介紹的很細,不然就要花太多的時間啦。
02 c++中的建構函式分類
c++中的建構函式主要有下面幾種:
其中轉換建構函式、顯式建構函式、拷貝建構函式、移動建構函式需要仔細講一下。
什麼是轉換建構函式和顯式建構函式?
看下面一段**:
#include #include using namespace std;class dog dog(const char* _name): name(_name) {}public:string name;};int main()
經過驗證,這裡**是可以正常編譯執行的,看一下16行: 你是不是很疑惑,為什麼可以將乙個常量字串賦值為dog型別的物件呢?
其實編譯器自動做了隱式型別轉換,呼叫了轉換建構函式了,所以程式沒有問題。所以轉換建構函式的定義就出來了:只含有乙個引數,並且該引數不是類的const引用成員,這個建構函式就是轉換建構函式。
但是,這樣的寫法太讓人迷惑了,你也可以在建構函式前面加上explicit關鍵字,宣告該建構函式不允許被隱式呼叫(第8行),然後上面的程式編譯就會報錯了。explitcit的用法如下:
什麼是拷貝建構函式和移動建構函式?
拷貝建構函式顧名思義就是在發生物件拷貝的時候呼叫的了,一般拷貝建構函式的寫法如下(為什麼我就不解釋了,看不明白的需要補一下c++基礎了):
mystring(const mystring& str) len = str.len; data = new char[len+1]; memcpy(data, str.data, len); data[len] = '0'; }
所以,拷貝建構函式在進行物件拷貝的時候採用的方式是"深拷貝",啥意思? 就是我申請乙個新的記憶體空間,然後把你的內容全部拷貝在我自己的內容空間裡面,然後你做了任何修改對我都沒有影響,拷貝的很徹底。與深拷貝的對應還有淺拷貝,有興趣的自己去查一下吧,這裡就不多說了。
深拷貝有自己的優點,但是也有缺陷。如果我們在拷貝臨時物件的時候,還是採用深拷貝的話,那麼我就要: 申請記憶體、拷貝內容、釋放臨時物件。這樣效率還是比較低的。
c++11為了解決臨時物件的拷貝效率的問題,引入了右值引用和移動語義。
媽的,都是什麼鬼? 如果要細講的話,這一篇文章估計百分之八十的內容都是關於它的了,所以這一篇文章就不細講了。只大概的介紹一下。
有什麼用呢? 先來看一下移動拷貝建構函式的寫法:
mystring(mystring&& str)
上面的移動拷貝建構函式仍然是拷貝str,但是沒有做深拷貝,只是拷貝了str的data指標,然後將str.data置為空。相當於我把str的data的內容偷了過來。這樣,就避免了記憶體空間的申請和拷貝的效率,效率自然就高了。
移動建構函式的引數是乙個右值引用,因此在引數傳入時要將左值轉換為右值,使用std::move()來實現。
值得注意的是,移動語義改善了臨時物件拷貝的效率,由於把臨時物件內部的指標變數偷了過去,所以經移動拷貝之後,臨時物件就失效了。
03 mystring類的**實現
class mystring // 帶參建構函式 mystring(const char* _data) // 拷貝建構函式 mystring(const mystring& str) len = str.len; data = new char[len+1]; memcpy(data, str.data, len); data[len] = '0'; } // 拷貝賦值函式 mystring& operator=(const mystring& str) len = str.len; data = new char[len+1]; memcpy(data, str.data, len); data[len] = '0'; return *this; } // 移動建構函式 mystring(mystring&& str) // 移動賦值函式 mystring& operator=(mystring&& str) len = str.len; data = str.data; // 淺拷貝,直接將記憶體移動過來 str.len = 0; str.data = nullptr; // 移動拷貝之後,臨時物件失效了 return *this; } // 析構函式 virtual ~mystring() } // 過載》 friend istream& operator>>(istream& in, mystring& str) // 過載<< friend ostream& operator<> str1 >> str2 >> str3;mystring str_1_copy(str1);// 呼叫拷貝建構函式cout << "str_1_copy is: " << str_1_copy << endl;mystring str_2_copy(std::move(str2));// 呼叫移動拷貝建構函式cout << "str_2_copy is: " << str_2_copy << endl;mystring str4, str5;str4 = str1;// 呼叫賦值建構函式cout << "str4 is: " << str4 << endl;str5 = std::move(str3);cout << "str5 is: " << str5 << endl;// 呼叫移動賦值建構函式 return 0;}
執行結果分析如下:
04 小結
這篇文章主要還是介紹c++中的建構函式,對於c++11中引入的移動語義介紹的比較少,恰巧我個人覺得c++中的移動語義和完美**這兩個問題也是比較難以理解的概念,所以在這裡先埋下乙個伏筆,後面有時間了再專門用一到兩篇文章介紹移動語義std::move()。
如果c++基礎比較薄弱的童鞋不理解也沒有關係,就當個玩笑看一下,先去補一下c++基礎。移動語義這個概念,研究生期間做專案全是用的c++也沒有遇到。
C 中構造函式呼叫建構函式
include include using namespace std struct cls cls int main 列印結果是不定的,不一定為0 奇怪的地方在於建構函式中呼叫了自己的另乙個建構函式 我們知道,當定義乙個物件時,會按順序做2件事情 1 分配好記憶體 非靜態資料成員是未初始化的 2 ...
C 中構造函式呼叫建構函式
include stdlib.h include iostream using namespace std struct clscls int main 列印結果是不定的,不一定為0 奇怪的地方在於建構函式中呼叫了自己的另乙個建構函式 我們知道,當定義乙個物件時,會按順序做2件事情 1 分配好記憶體...
c 中構造函式呼叫建構函式
c 中建構函式完成的工作分兩步 1 分配空間 2 初始化空間 構造函式呼叫建構函式。class a a int a private int a 這樣會導致,a 中先分配了空間,然後呼叫a 0 又建立了乙個臨時物件,然後初始化為0,而原物件則沒有初始化。這種問題在類中有指標需要分配空間時會導致災難。從...