一起聊聊C++中的特殊成員函數(shù)
一:背景
在C#中要說類默認給我們定義的特殊成員函數(shù),莫過于構(gòu)造函數(shù),但在 C++ 中這樣的特殊函數(shù)高達 6 種,有必要整合一下聊一聊。
二:特殊成員函數(shù)
1. 默認構(gòu)造函數(shù)
和 C# 一樣,很多書中都說,如果用戶沒有定義 構(gòu)造函數(shù),那么編譯器會給我們定義一個,參考下面的例子:
class Person { public: string name; int age; }; int main() { Person person; }
接下來觀察下匯編代碼,看下有沒有調(diào)用 默認構(gòu)造函數(shù) .
Person person;
003E32EF lea ecx,[person]
003E32F2 call Person::Person (03E15EBh)
對于 C# 學(xué)習(xí)者來說有點懵哈,定義了就相當于new了, 哈哈,這是因為C++默認都是值類型哈,不過這里有必要澄清一下,并不一定所有情況都會調(diào)用默認構(gòu)造函數(shù),因為C++的匯編生成由各自 編譯器 來決定,如果 編譯器 覺得沒必要調(diào)用構(gòu)造函數(shù) 那它就會把這一步省掉來加速性能,那什么時候不會調(diào)呢? 參考如下代碼。
class Person { public: void show() { printf("show!"); } }; int main() { Person person; person.show(); }
接下來看下匯編代碼。
person.show();
00E73F4F lea ecx,[person]
00E73F52 call Person::show (0E713B6h)
可以清楚的看到,這種情況下調(diào)用構(gòu)造函數(shù)其實沒有必要,所以編譯器就干脆省略了。
2. 析構(gòu)函數(shù)
在C#中析構(gòu)函數(shù) 是由CLR負責(zé)管理,在C++中沒有托管這個概念,所以默認只能是結(jié)束作用域之前,自動調(diào)用析構(gòu)函數(shù)釋放,參考如下圖:
3. 賦值構(gòu)造函數(shù)
剛才也說到了,在 C++ 中甭管是 class 還是 struct 默認都是值類型,既然是值類型就存在stack copy
的情況,在 C# 中也是因為重寫了 Equals
和 GetHashCode
來實現(xiàn)的值copy,接下來簡單看下代碼:
class Person { public: string name; int age; }; int main() { Person p1 = { "jack",20 }; Person p2(p1); }
再看下 Person p2(p1)
的匯編代碼。
Person p2(p1);
000F80A2 lea eax,[p1]
000F80A5 push eax
000F80A6 lea ecx,[p2]
000F80A9 call Person::Person (0F15C3h)
從匯編中可以看到調(diào)用了 Person::Person (0F15C3h)
函數(shù),請注意,這個不是構(gòu)造函數(shù),而是 賦值構(gòu)造函數(shù), 可以調(diào)試下去看看哦。。。 截圖如下:
值得說一下的是,C++ 默認提供的賦值構(gòu)造函數(shù)是淺copy,如果要實現(xiàn)深 copy 的話,或者有一些自定義的邏輯,建議自己實現(xiàn)一下。
class Person { public: string name; int age; public: Person(string name, int age) :name(name), age(age) {} Person(const Person& p) { name = p.name; age = p.age; } }; int main() { Person p1 = { "aaaaaaaaaaaaaaaaaaaaaaaaaaa",20 }; Person p2(p1); }
4. 賦值運算符
在 C# 中值類型, 匿名類型, Record
都是重寫過 Equals
及 =
運算符,所以可以在這些類型上用 =
, 其實在 C++ 中也可以在 class 之間進行賦值,因為編譯器會幫我們重寫運算符 =
,如何看出來呢?先看下代碼:
class Person { public: string name; int age; public: Person(string name, int age) :name(name), age(age) {} Person(const Person& p) { name = p.name; age = p.age; } }; int main() { Person p1 = { "aaaaaaaaaaaaaaaaaaaaaaaaaaa",20 }; Person p2 = { "bbbbbbbbbbbbbbbbbbbbbbbbbbb",22 }; p2 = p1; }
最后一句的 p2 = p1
之所以能成功是因為 =
被重寫了,參考匯編代碼。
p2 = p1;
00FD967C lea eax,[p1]
00FD967F push eax
00FD9680 lea ecx,[p2]
00FD9683 call Person::operator= (0FD161Dh)
如果需要自定義,可以自己重寫。
class Person { public: string name; int age; public: Person(string name, int age) :name(name), age(age) {} Person(const Person& p) { name = p.name; age = p.age; } Person& operator = (const Person& p) { name = p.name; age = p.age; return *this; } }; int main() { Person p1 = { "aaaaaaaaaaaaaaaaaaaaaaaaaaa",20 }; Person p2 = { "bbbbbbbbbbbbbbbbbbbbbbbbbbb",22 }; p2 = p1; }
到此這篇關(guān)于一起聊聊C++中的特殊成員函數(shù)的文章就介紹到這了,更多相關(guān)C++ 特殊成員函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MFC創(chuàng)建模態(tài)對話框和非模態(tài)對話框的方法
這篇文章主要介紹了MFC創(chuàng)建模態(tài)對話框和非模態(tài)對話框的方法,需要的朋友可以參考下2014-07-07QT線程池的使用(QThreadPool類和QRunnable類)
本文主要介紹了QT線程池的使用(QThreadPool類和QRunnable類),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04