# C++類的默認成員函數有哪些
## 引言
在C++面向對象編程中,類(class)是構建程序的基礎模塊。當我們定義一個類時,即使不顯式聲明某些成員函數,編譯器也會自動為我們生成一些默認的成員函數。這些默認成員函數在對象的生命周期中扮演著重要角色,理解它們的存在和行為對于編寫正確、高效的C++代碼至關重要。
本文將詳細探討C++類中的6個默認成員函數,包括它們的特性、使用場景以及注意事項,幫助開發者更好地掌握C++對象模型的核心機制。
---
## 一、默認成員函數概述
### 1.1 什么是默認成員函數
默認成員函數是指當類定義中未顯式聲明時,由編譯器自動生成的成員函數。這些函數包括:
1. 默認構造函數
2. 默認析構函數
3. 默認拷貝構造函數
4. 默認拷貝賦值運算符
5. 默認移動構造函數(C++11引入)
6. 默認移動賦值運算符(C++11引入)
### 1.2 生成條件
這些函數僅在**需要時**才會被生成,且滿足以下條件:
- 類中沒有用戶自定義的對應函數
- 沒有被`= delete`顯式刪除
- 類的所有成員和基類支持相應操作
```cpp
class Example {
// 編譯器將根據需要生成所有默認成員函數
};
ClassName()
class Widget {
public:
int x; // 未初始化
std::string s; // 調用默認構造函數
};
Widget w; // 使用默認構造函數
= default
顯式請求生成~ClassName()
class ResourceHolder {
FILE* file;
public:
~ResourceHolder() {
if(file) fclose(file); // 需要自定義資源管理
}
};
ClassName(const ClassName&)
class String {
char* data;
public:
// 默認拷貝構造函數會導致多個對象共享同一內存
// 通常需要自定義深拷貝
String(const String& other) :
data(new char[strlen(other.data)+1]) {
strcpy(data, other.data);
}
};
如果類需要自定義以下任一函數,通常需要全部三個: 1. 析構函數 2. 拷貝構造函數 3. 拷貝賦值運算符
ClassName& operator=(const ClassName&)
*this
以支持鏈式賦值class Array {
int* ptr;
size_t size;
public:
// 不安全的自賦值處理
Array& operator=(const Array& other) {
delete[] ptr;
ptr = new int[other.size];
size = other.size;
std::copy(other.ptr, other.ptr+size, ptr);
return *this;
}
};
a = a
)ClassName(ClassName&&) noexcept
std::move
class Buffer {
char* data;
size_t length;
public:
Buffer(Buffer&& other) noexcept :
data(other.data), length(other.length) {
other.data = nullptr; // 置空源對象
other.length = 0;
}
};
對于資源管理類,建議同時提供: 1. 析構函數 2. 拷貝構造函數 3. 拷貝賦值運算符 4. 移動構造函數 5. 移動賦值運算符
ClassName& operator=(ClassName&&) noexcept
Buffer& operator=(Buffer&& other) noexcept {
if(this != &other) {
delete[] data; // 釋放現有資源
data = other.data;
length = other.length;
other.data = nullptr;
other.length = 0;
}
return *this;
}
noexcept
以便標準庫優化使用= default
顯式請求編譯器生成默認實現:
class Defaulted {
public:
Defaulted() = default;
Defaulted(const Defaulted&) = default;
~Defaulted() = default;
};
使用= delete
禁止特定操作:
class NonCopyable {
public:
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
函數 | 生成條件 |
---|---|
默認構造函數 | 無任何構造函數 |
析構函數 | 總是生成 |
拷貝構造函數 | 無用戶定義拷貝操作 |
拷貝賦值運算符 | 無用戶定義拷貝賦值 |
移動操作 | 無用戶定義拷貝/移動/析構函數 |
class BestPractice {
public:
// 顯式聲明所有特殊成員函數
BestPractice() = default;
~BestPractice() = default;
BestPractice(const BestPractice&) = default;
BestPractice& operator=(const BestPractice&) = default;
BestPractice(BestPractice&&) noexcept = default;
BestPractice& operator=(BestPractice&&) noexcept = default;
};
理解C++默認成員函數是掌握對象生命周期管理的關鍵。從C++98的三法則到C++11的五法則,語言演進不斷改進對象操作的效率和安全性。合理利用這些默認函數可以減少代碼冗余,同時通過自定義實現可以精確控制對象行為。開發者應當根據類的具體需求,選擇適當的策略來處理這些特殊成員函數。
“Effective C++的核心在于理解C++默默編寫并調用了哪些函數。” —— Scott Meyers “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。