一:背景
在 C# 中要說類默認給我們定義的特殊成員函式,莫過于 建構式,但在 C++ 中這樣的特殊函式高達 6 種,有必要整合一下聊一聊,
二:特殊成員函式
1. 默認建構式
和 C# 一樣,很多書中都說,如果用戶沒有定義 建構式,那么編譯器會給我們定義一個,參考下面的例子:
class Person {
public:
string name;
int age;
};
int main()
{
Person person;
}
接下來觀察下匯編代碼,看下有沒有呼叫 默認建構式 .
Person person;
003E32EF lea ecx,[person]
003E32F2 call Person::Person (03E15EBh)
對于 C# 學習者來說有點懵哈,定義了就相當于new了, 哈哈,這是因為 C++ 默認都是值型別哈,不過這里有必要澄清一下,并不一定所有情況都會呼叫 默認建構式,因為 C++ 的匯編生成由各自 編譯器 來決定,如果 編譯器 覺得沒必要呼叫 建構式 那它就會把這一步省掉來加速性能,那什么時候不會調呢? 參考如下代碼,
class Person {
public:
void show() {
printf("show!");
}
};
int main()
{
Person person;
person.show();
}
接下來看下匯編代碼,
person.show();
00E73F4F lea ecx,[person]
00E73F52 call Person::show (0E713B6h)
可以清楚的看到,這種情況下呼叫 建構式 其實沒有必要,所以編譯器就干脆省略了,
2. 解構式
在 C# 中 解構式 是由 CLR 負責管理,在 C++ 中沒有托管這個概念,所以默認只能是結束作用域之前,自動呼叫 解構式 釋放,參考如下圖:
3. 賦值建構式
剛才也說到了,在 C++ 中甭管是 class 還是 struct 默認都是值型別,既然是值型別就存在stack copy 的情況,在 C# 中也是因為重寫了 Equals 和 GetHashCode 來實作的值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)
從匯編中可以看到呼叫了 Person::Person (0F15C3h) 函式,請注意,這個不是 建構式,而是 賦值建構式 ??, 可以除錯下去看看哦,,, 截圖如下:
值得說一下的是,C++ 默認提供的 賦值建構式 是淺copy,如果要實作深 copy 的話,或者有一些自定義的邏輯,建議自己實作一下,
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;
}
在 C++ 11 中還有特殊的 移動建構式 和 移動賦值建構式, 這個還需要理解 左值 和 右值參考,篇幅有限,放到后面和大家聊了哈,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/498674.html
標籤:C++
上一篇:java反射機制(1)
下一篇:IOS OpenGL ES GPUImage 影像顯示亮度最高的像素,其他為黑 GPUImageThresholdedNonMaximumSuppressionFilter
