類的六個默認成員函數

如果一個類中什么成員都沒有,簡稱為空類。

空類中真的什么都沒有嗎?并不是,任何類在什么都不寫時,編譯器會自動生成以下6個默認成員函數。

默認成員函數:用戶沒有顯式實現,編譯器會生成的成員函數稱為默認成員函數。

一.構造函數

?構造函數(Constructor)

?構造函數是 C++ 中用于初始化對象的特殊成員函數,它在對象創建時自動調用。以下是構造函數的全面解析:

1. 基本概念

?

- 作用:初始化對象成員變量

- 特點:

- 函數名與類名相同

- 無返回值(連 ?void? 都沒有)

- 支持重載(一個類可以有多個構造函數)

- 調用時機:

- 對象定義時(?Class obj;?)

- 動態創建對象時(?new Class()?)

- 臨時對象創建時(?Class()?)

?

2. 構造函數的類型

?

(1) 編譯器生成的默認構造函數

?

- 觸發條件:當類沒有定義任何構造函數時,編譯器自動生成

- 行為:

- 對基本類型(?int?/?float? 等)不初始化(值隨機)

- 對類類型成員調用其默認構造函數

?

class DefaultExample

{

public:

? ? // 編譯器自動生成默認構造函數

? ? int val; // 未初始化

};

?

void demo()

{

? ? DefaultExample obj; // val的值隨機

}

?

?

(2) 自定義默認構造函數(無參構造)

?

class MyClass

{

public:

? ? // 顯式定義默認構造函數

? ? MyClass() : x(0), y(0) {}?

private:

? ? int x, y;

};

?

?

(3) 全缺省構造函數

?

- 所有參數都有默認值,可以替代默認構造函數

?

class AllDefault

{

public:

? ? // 全缺省構造函數(也是默認構造函數)

? ? AllDefault(int a = 0, int b = 0) : x(a), y(b) {}

private:

? ? int x, y;

};

?

void demo()

{

? ? AllDefault obj1; // 等效于 AllDefault(0, 0)

? ? AllDefault obj2(5); // AllDefault(5, 0)

}

?

?

(4) 部分缺省構造函數

?

class PartialDefault

{

public:

? ? // 部分缺省參數

? ? PartialDefault(int a, int b = 10) : x(a), y(b) {}

private:

? ? int x, y;

};

?

void demo()

{

? ? PartialDefault obj(5); // PartialDefault(5, 10)

? ? PartialDefault obj2(1, 2);

}

?

?

?

?

3. 必須自定義構造函數的場景
?
在 C++ 中,以下情況必須手動編寫構造函數,不能依賴編譯器生成的默認構造函數:
?
?
?
_類包含引用類型成員
?
- 原因:引用必須在初始化時綁定到一個對象,且之后不能更改綁定目標。
- 解決方案:必須通過構造函數的初始化列表顯式初始化引用成員。
?
_類包含 const 常量成員
?
- 原因:const 成員必須在對象構造時初始化,且之后不可修改。
- 解決方案:必須在構造函數的初始化列表中初始化 const 成員。
?
_類需要管理動態資源
?
- 原因:默認構造函數不會自動分配堆內存、打開文件等資源。
- 典型場景:
- 成員包含指針并需要動態分配內存(如 ?int* data = new int[100]?)
- 需要初始化文件句柄、數據庫連接等外部資源
- 解決方案:在構造函數中顯式申請資源,并在析構函數中釋放。
?
_類成員需要特定初始值
?
- 原因:編譯器生成的默認構造函數不會初始化基本類型成員(如 ?int?/?float??等)。
- 解決方案:手動定義構造函數,確保成員初始化為預期值(例如初始化為 0 或空字符串)。
?
_類繼承體系中基類沒有默認構造函數
?
- 原因:如果基類只有帶參數的構造函數,派生類必須顯式調用基類構造函數。
- 解決方案:在派生類構造函數的初始化列表中調用基類的構造函數。
?
_需要禁止某些對象的構造方式
?
- 場景:
- 希望強制使用特定參數構造對象(如必須傳入 ID)
- 單例模式中需要私有化構造函數
- 解決方案:手動定義構造函數并刪除默認版本(如 ?ClassName() = delete?)

4. 初始化列表 vs 構造函數體內賦值

?

方式 特點?

初始化列表 - 在對象構造時直接初始化成員 - 必須用于引用/const成員初始化?

構造函數體內賦值 - 實際上是先默認構造再賦值 - 對非基本類型有額外性能開銷?

?

class InitDemo

{

public:

? ? // 推薦:初始化列表

? ? InitDemo(int a, std::string s) : num(a), str(s) {}

? ??

? ? // 不推薦:構造函數內賦值

? ? InitDemo(int a) {?

? ? ? ? num = a; // 先執行string的默認構造,再賦值

? ? ? ? str = "default";

? ? }

? ??

private:

? ? int num;

? ? std::string str; // 類類型成員

};

?

?

?

?

5. 特殊構造函數

?

(1) 委托構造函數(C++11)

?

class Delegating

{

public:

? ? // 主構造函數

? ? Delegating(int a, double b) : x(a), y(b) {}

? ??

? ? // 委托給主構造函數

? ? Delegating() : Delegating(0, 0.0) {}?

private:

? ? int x;

? ? double y;

};

?

?

(2) explicit 構造函數

?

- 禁止隱式類型轉換

?

class ExplicitDemo

{

public:

? ? explicit ExplicitDemo(int x) : val(x) {} // 必須顯式調用

};

?

void demo()

{

? ? // ExplicitDemo obj = 5; // 錯誤!禁止隱式轉換

? ? ExplicitDemo obj(5); // 正確

}

?

6. 構造函數的調用順序

?

1.?基類構造函數(如果存在繼承)

2.?成員變量的構造函數(按聲明順序)

3.?當前類的構造函數體

?

class Member

{

public:

? ? Member() { std::cout << "Member構造\n"; }

};

?

class Base

{

public:

? ? Base() { std::cout << "Base構造\n"; }

};

?

class Demo : public Base

{

public:

? ? Demo() : m(), Base() {?

? ? ? ? std::cout << "Demo構造\n";?

? ? }

private:

? ? Member m;

};

?

// 輸出順序:

// Base構造 → Member構造 → Demo構造

?

7. 實際應用建議

?

_優先使用初始化列表:尤其對類類型成員

_對單參數構造函數加?explicit?:避免意外類型轉換

_資源管理類遵循三五法則:如果需要自定義析構函數,通常也需要自定義拷貝構造和賦值運算符

_避免在構造函數中調用虛函數:此時虛函數機制未完全建立

?

class ResourceOwner

{

public:

? ? explicit ResourceOwner(size_t size)?

? ? ? ? : data(new int[size]), size(size) {}

? ??

? ? ~ResourceOwner() { delete[] data; }

? ??

? ? // 三五法則:需要自定義拷貝控制成員

? ? ResourceOwner(const ResourceOwner&) = delete;

? ? ResourceOwner& operator=(const ResourceOwner&) = delete;

? ??

private:

? ? int* data;

? ? size_t size;

};

?

?

二.析構函數

?析構函數是 C++ 中用于對象銷毀時自動調用的特殊成員函數,負責資源清理工作

1. 基本概念

?

- 作用:釋放對象占用的資源(內存/文件/鎖等)

- 特點:

- 函數名為 ?~類名?

- 無參數無返回值

- 不可重載(每個類只能有一個析構函數)

- 調用時機:

- 對象離開作用域時(棧對象)

- ?delete? 動態對象時(堆對象)

- 容器銷毀時(如 ?vector? 析構會調用元素析構)

?

class FileHandler

{

public:

? ? FileHandler()

? ?{

? ? file = fopen("data.txt", "r");

? ? }

? ? ~FileHandler()

? ? ? {?

? ? ? ? if(file) fclose(file); // 必須手動關閉文件

? ? ? ? std::cout << "資源已釋放\n";?

? ? ? }

private:

? ? FILE* file;

};

?

2. 必須自定義析構函數的場景

?

?

// 場景1:動態內存管理

class MemoryPool

{

public:

? ? MemoryPool(size_t size) { data = new int[size]; }

? ? ~MemoryPool() { delete[] data; } // 必須自定義

private:

? ? int* data;

};

?

// 場景2:文件資源管理

class DatabaseConn

{

public:

? ? ~DatabaseConn() { disconnect(); } // 確保連接關閉

};

?

// 場景3:多態基類

class Base

{

public:

? ? virtual ~Base() = default; // 虛析構函數!!!

};

?

class Derived : public Base

{

? ? ~Derived() override { /* 清理派生類資源 */ }

};

?

?

?

?

3. 默認析構函數的問題

?

問題1:淺拷貝導致雙重釋放

?

class ShallowCopy

{

public:

? ? ShallowCopy(int size) { data = new int[size]; }

? ? ~ShallowCopy() { delete[] data; } // 危險!

? ??

private:

? ? int* data;

};

?

void demo()

{

? ? ShallowCopy obj1(10);

? ? ShallowCopy obj2 = obj1; // 淺拷貝:兩個對象共享data指針

? ? // 析構時會導致同一內存被釋放兩次 → 程序崩潰

}

?

?

解決方案:實現拷貝控制(拷貝構造+賦值運算符)或禁用拷貝(C++11)

?

class SafeCopy

{

public:

? ? // 方法1:禁用拷貝

? ? SafeCopy(const SafeCopy&) = delete;

? ? SafeCopy& operator=(const SafeCopy&) = delete;

? ??

? ? // 方法2:實現深拷貝

? ? SafeCopy(const SafeCopy& other)

? ?{

? ? ? ? data = new int[other.size];

? ? ? ? std::copy(other.data, other.data+other.size, data);

? ? }

};

?

?

問題2:部分資源泄漏

?

class ResourceLeak

? {

public:

? ? ResourceLeak()

? ?{?

? ? ? ? res1 = new int[100];?

? ? ? ? res2 = new int[200];?

? ? }

? ? ~ResourceLeak() { delete[] res1; } // res2泄漏!

private:

? ? int *res1, *res2;

};

?

?

解決方案:使用 RAII 對象管理資源(如 ?std::unique_ptr?)

?

class SafeResource

{

? ? std::unique_ptr<int[]> res1;

? ? std::unique_ptr<int[]> res2;

public:

? ? SafeResource() :?

? ? ? ? res1(std::make_unique<int[]>(100)),

? ? ? ? res2(std::make_unique<int[]>(200)) {}

? ? // 無需顯式析構函數!

};

?

?

?

?

4. 析構函數調用順序

?

1.?執行析構函數體:當前類的清理代碼

2.?調用成員變量的析構函數(按聲明逆序)

3.?調用基類析構函數(若存在繼承,從派生類向基類析構)

?

class Member

{

public:

? ? ~Member() { std::cout << "Member析構\n"; }

};

?

class Base

{

public:

? ? virtual ~Base() { std::cout << "Base析構\n"; }

};

?

class Derived : public Base

{

public:

? ? ~Derived() override

? ?{

? ?std::cout << "Derived析構\n";

? ?}

private:

? ? Member m;

};

?

// 調用示例:

Base* obj = new Derived();

delete obj;?

?輸出順序:

? ?Derived析構 → Member析構 → Base析構

?

?

5. 最佳實踐

?

1.?RAII原則:資源獲取即初始化,通過對象生命周期管理資源

2.?三五法則:若自定義析構函數,通常需要同時處理拷貝/移動操作

3.?多態基類聲明虛析構函數:防止通過基類指針刪除派生類對象時資源泄漏

4.?優先使用智能指針:避免手動內存管理錯誤

?

// 現代C++推薦寫法

class ModernExample

{

? ? std::unique_ptr<int[]> data; // 自動管理內存

? ? std::mutex mtx; // RAII管理鎖

public:

? ? ModernExample() : data(std::make_unique<int[]>(100)) {}

? ? // 無需顯式析構函數!

};

關鍵總結

?

- 必須自定義析構函數:當類管理動態分配的資源或需要確保資源釋放時

- 危險陷阱:默認淺拷貝會導致雙重釋放,需通過深拷貝或禁用拷貝避免

- 多態必備:基類必須聲明虛析構函數,否則通過基類指針刪除派生類對象會導致派生類資源泄漏

- 現代替代方案:優先使用智能指針和STL容器替代裸指針/手動資源管理

三.拷貝構造函數
?
拷貝構造函數是C++中的一種特殊構造函數,用于創建一個新對象作為現有對象的副本。
?
基本語法
?
class MyClass

{
public:
? ? // 拷貝構造函數
? ? MyClass(const MyClass& other)

? ?{
? ? ? ? // 復制other的成員到當前對象
? ? }
};
?
?
特點
?
1.?參數是對同類型對象的const引用
2.?通常不應修改源對象,因此參數通常是const
3.?如果沒有顯式定義,編譯器會自動生成一個默認的拷貝構造函數
?
使用場景
?
拷貝構造函數在以下情況下被調用:
?
1.?用一個對象初始化另一個對象時:
MyClass obj1;
MyClass obj2 = obj1; // 調用拷貝構造函數
MyClass obj3(obj1); ?// 調用拷貝構造函數
?
2.?對象作為函數參數按值傳遞時:
void func(MyClass obj);

MyClass original;
func(original); // 調用拷貝構造函數
?
3.?函數返回對象時(可能被編譯器優化):
MyClass createObject()

{
? ? MyClass obj;
? ? return obj; // 可能調用拷貝構造函數
}
?
?
深拷貝與淺拷貝
?
1.?淺拷貝:僅復制指針值,不復制指針指向的內容(默認拷貝構造函數的行為)
2.?深拷貝:復制指針指向的內容,需要自定義拷貝構造函數
?
class DeepCopyExample

{
? ? int* data;
public:
? ? // 深拷貝構造函數
? ? DeepCopyExample(const DeepCopyExample& other)

? ? {
? ? ? ? data = new int(*other.data); // 分配新內存并復制值
? ? }
};
?
?
禁用拷貝
?
可以通過將拷貝構造函數聲明為delete來禁止拷貝:
?
class NonCopyable

{
public:
? ? NonCopyable(const NonCopyable&) = delete;
};
?
?
最佳實踐
?
1.?對于包含動態分配資源的類,應實現自定義拷貝構造函數
2.?對于不應被拷貝的類,應顯式禁用拷貝構造函數
3.?考慮使用移動語義(C++11引入)來提高性能
?
四.賦值運算符重載 (Copy Assignment Operator)

?

賦值運算符重載是C++中允許類自定義對象間賦值行為的特性,通常與拷貝構造函數一起使用。

?

基本語法

?

class MyClass

{

public:

? ? // 賦值運算符重載

? ? MyClass& operator=(const MyClass& other) {

? ? ? ? if (this != &other)

? ? ? ?{ // 防止自賦值

? ? ? ? ? ? // 復制other的成員到當前對象

? ? ? ? }

? ? ? ? return *this; // 支持鏈式賦值

? ? }

};

?

?

特點

?

1.?必須是成員函數,不能是友元函數

2.?通常返回當前對象的引用以支持鏈式賦值

3.?參數是對同類型對象的const引用

4.?需要處理自賦值情況

?

使用場景

?

當對象被賦值時自動調用:

?

MyClass obj1, obj2;

obj1 = obj2; // 調用賦值運算符重載

?

拷貝構造函數與拷貝賦值運算符的區別
?
拷貝構造函數和拷貝賦值運算符雖然都用于對象拷貝,但在本質上有重要區別:
?
1. 根本目的不同
?
- 拷貝構造函數:用于在創建新對象時,用已有對象初始化它。這是對象的"出生"過程。
- 拷貝賦值運算符:用于兩個已存在對象之間的賦值操作。這是對象的"改變"過程。
?
2. 調用時機不同
?
拷貝構造函數在以下情況調用:
?
MyClass obj1; ? ? ? ? ? ? // 默認構造
MyClass obj2(obj1); ? ? ? // 直接調用拷貝構造
MyClass obj3 = obj1; ? ? ?// 這也是調用拷貝構造
MyClass func(MyClass o); ?// 參數傳遞時可能調用拷貝構造
?
?
拷貝賦值運算符在以下情況調用:
?
MyClass obj1, obj2; ?// 默認構造
obj1 = obj2; ? ? ? ? // 調用賦值運算符
?
?
3. 對象生命周期不同
?
- 拷貝構造:目標對象尚未存在,需要在構造過程中初始化
- 拷貝賦值:目標對象已經存在,需要先清理原有資源再賦新值
?
4. 實現要點不同
?
拷貝構造的實現:
?
MyClass(const MyClass& other)

{
? ? // 只需關心從other復制到新對象
? ? data = new int(*other.data); // 深拷貝示例
}
?
?
拷貝賦值的實現:
?
MyClass& operator=(const MyClass& other)

{
? ? if(this != &other)

? ? { ?// 1. 檢查自賦值
? ? ? ? delete data; ? ? ?// 2. 釋放原有資源
? ? ? ? data = new int(*other.data); // 3. 深拷貝
? ? }
? ? return *this; ? ? ? ?// 4. 返回引用
}
?
?
5. 資源管理差異
?
- 拷貝構造:只需分配新資源并復制
- 拷貝賦值:需要先釋放舊資源,再分配新資源,還要處理自賦值情況
?
6. 返回值不同
?
- 拷貝構造:沒有返回值
- 拷貝賦值:通常返回對象引用以支持鏈式賦值(a = b = c)
?
實際應用建議
?
1.?遵循"三大法則":如果實現了其中任何一個(拷貝構造、拷貝賦值或析構),通常需要實現全部三個
2.?對于資源管理類,必須同時正確實現兩者
3.?現代C++中可考慮使用"復制交換慣用法"簡化實現
4.?不需要拷貝時應顯式禁用(=delete)
?

深拷貝實現示例

?

class DeepCopyExample

{

? ? int* data;

public:

? ? // 賦值運算符重載

? ? DeepCopyExample& operator=(const DeepCopyExample& other)

{

? ? ? ? if (this != &other)

? ? ? ?{

? ? ? ? ? ? delete data; // 釋放原有資源

? ? ? ? ? ? data = new int(*other.data); // 分配新內存并復制

? ? ? ? }

? ? ? ? return *this;

? ? }

};

?

?

復制交換慣用法 (Copy-and-Swap Idiom)

?

更安全和高效的實現方式:

?

class MyClass

{

? ? // ... 其他成員 ...

public:

? ? friend void swap(MyClass& first, MyClass& second) noexcept

? ? ?{

? ? ? ? // 交換所有成員

? ? ? ? using std::swap;

? ? ? ? swap(first.data, second.data);

? ? }

?

? ? MyClass& operator=(MyClass other) noexcept

? ? {

? ? ? ? swap(*this, other); // 交換當前對象與參數

? ? ? ? return *this; // other離開作用域時會自動清理舊資源

? ? }

};

?

?

禁用賦值

?

可以通過聲明為delete來禁止賦值:

?

class NonAssignable

{

public:

? ? NonAssignable& operator=(const NonAssignable&) = delete;

};

五.const成員函數
?
const成員函數是C++中保證函數不會修改對象狀態的重要機制,它在類設計中扮演著關鍵角色。
?
基本概念
?
定義方式
?
在成員函數聲明和定義的參數列表后添加?const?關鍵字:
?
class MyClass

{
public:
? ? // 聲明const成員函數
? ? void display() const;
? ??
? ? int getValue() const

? ? {
? ? ? ? return value; ?// 直接定義的const成員函數
? ? }
private:
? ? int value;
};

// 類外定義const成員函數
void MyClass::display() const

{
? ? // 函數實現
}
?
?
核心特性
?
1.?不可修改性:不能修改類的非mutable成員變量
2.?調用權限:可以被const和非const對象調用
3.?重載機制:可以與同名非const成員函數形成重載
?
使用場景
?
1. 訪問器方法(Getters)
?
class Student

{
? ? std::string name;
public:
? ? // const成員函數作為getter
? ? const std::string& getName() const

? ? ?{

? ? ? ? ?return name;

? ? ?}
};
?
?
2. 不修改對象狀態的工具函數
?
class Matrix

{
? ? double data[10][10];
public:
? ? // 計算行列式但不修改矩陣內容
? ? double determinant() const;
};
?
?
3. const對象接口
?
const Student s("Alice");
s.getName(); ?// 只能調用const成員函數
?
?
重要規則
?
1. 修改限制
?
class Counter

{
? ? int count;
? ? mutable int accessCount; ?// mutable例外
public:
? ? void increment() const

? ?{
? ? ? ? // count++; ?// 錯誤!不能修改非mutable成員
? ? ? ? accessCount++; ?// 正確:mutable成員可修改
? ? }
};
?
?
2. 重載決議
?
class TextBlock

? ?{
? ? std::string text;
public:
? ? // const版本
? ? const char& operator[](size_t pos) const

? ? {
? ? ? ? return text[pos];
? ? }
? ??
? ? // 非const版本
? ? char& operator[](size_t pos)

? ? {
? ? ? ? return text[pos];
? ? }
};

const TextBlock ctb("Hello");
TextBlock tb("World");
ctb[0]; ?// 調用const版本
tb[0]; ? // 調用非const版本
?
?
高級用法
?
1. 邏輯常量性
?
class CachedData

{
? ? mutable std::string cachedValue;
? ? bool cacheValid;
public:
? ? std::string getValue() const

? {
? ? ? ? if (!cacheValid)

? ? ? ?{
? ? ? ? ? ? // 雖然修改了成員,但不影響邏輯常量性
? ? ? ? ? ? cachedValue = computeValue();
? ? ? ? ? ? cacheValid = true;
? ? ? ? }
? ? ? ? return cachedValue;
? ? }
};
?
?
2. 返回類型優化
?
class BigData

{
? ? std::vector<int> data;
public:
? ? // 返回const引用避免拷貝
? ? const std::vector<int>& getData() const

? ? {

? ? ? ?return data;

? ? ? }
};
?
?
最佳實踐
?
1.?80%原則:80%的成員函數應該聲明為const
2.?const一致:相關函數應提供const和非const版本
3.?避免cast:不要用const_cast去掉const性質
4.?mutable慎用:只在真正不影響邏輯狀態時使用
5.?文檔說明:對mutable成員的使用添加注釋說明
?

C++中的const成員

?

const成員是指被?const?關鍵字修飾的類成員,包括const成員變量和const成員函數。

?

一、const成員變量

?

1. 特點

?

- 必須在構造函數的初始化列表中初始化

?

- 初始化后值不可修改

?

- 每個對象的const成員可以有不同的值

?

2. 聲明與初始化

?

cpp

class MyClass

{

public:

? ? const int size; // const成員變量聲明

? ??

? ? // 必須在初始化列表中初始化

? ? MyClass(int s) : size(s) {}??

? ??

? ? // 錯誤!不能在構造函數體內賦值

? ? // MyClass(int s) { size = s; }??

};

?

?

3. 使用場景

?

- 類中需要保持不變的配置參數

?

- 對象特有的常量值

?

- 防止意外修改的重要成員

?

二、const成員函數

?

1. 特點

?

- 在函數聲明和定義后加?const?關鍵字

?

- 不能修改類的任何非mutable成員變量

?

- 可以訪問但不能修改對象狀態

?

- 可以被const和非const對象調用

?

2. 語法

?

cpp

class MyClass

{

? ? int value;

public:

? ? // const成員函數

? ? int getValue() const

? ?{??

? ? ? ? return value; // 可以讀取但不能修改成員

? ? }

? ??

? ? // 錯誤!const成員函數不能修改成員

? ? // void setValue(int v) const { value = v; }

};

?

?

3. 使用場景

?

- 不修改對象狀態的getter方法

?

- 保證線程安全的成員函數

?

- 需要被const對象調用的方法

?

三、const對象

?

1. 特點

?

- 聲明為const的對象

?

- 只能調用const成員函數

?

- 所有成員變量被視為const

?

cpp

const MyClass obj(10);

int x = obj.getValue(); // 正確

// obj.setValue(20); // 錯誤!const對象不能調用非const方法

?

?

四、mutable成員

?

1. 特點

?

- 用?mutable?關鍵字修飾的成員變量

?

- 可以在const成員函數中被修改

?

- 通常用于不影響對象邏輯狀態的成員

?

2. 示例

?

cpp

class MyClass

{

? ? mutable int cache; // mutable成員

? ? int value;

public:

? ? int getValue() const

? ? {

? ? ? ? cache++; // 可以修改mutable成員

? ? ? ? return value;

? ? }

};

?

?

五、最佳實踐

?

1.?盡可能將不修改對象狀態的成員函數聲明為const

?

2.?const成員變量應在初始化列表中初始化

?

3.?對于需要頻繁修改的緩存或計數器使用mutable

?

4.?設計類時應考慮const正確性

?

5.?const成員函數可以重載非const版本

?

六.取地址及const取地址操作符重載

?

在C++中,我們可以重載取地址運算符(?operator&?)來定制對象地址獲取行為,這在某些特殊場景下非常有用。

?

基本語法

?

普通取地址運算符重載

?

class MyClass

{

public:

? ? MyClass* operator&()

? ? {

? ? ? ? return this; // 默認行為,通常不需要重載

? ? ? ? // 可以返回其他指針,但需謹慎

? ? }

};

?

?

const版本取地址運算符重載

?

class MyClass

{

public:

? ? const MyClass* operator&() const

? ?{

? ? ? ? return this; // const對象的取地址

? ? }

};

?

?

使用場景

?

1. 禁止獲取真實地址(封裝實現)

?

class NoAddress

{

private:

? ? static int dummy;

public:

? ? int* operator&() { return &dummy; } // 返回假地址

? ? const int* operator&() const

? ? ?{

? ? ? ?return &dummy;

? ? ?}

};

int NoAddress::dummy = 0;

?

?

2. 智能指針模擬

?

template<typename T>

class PtrWrapper

{

? ? T* ptr;

public:

? ? PtrWrapper(T* p) : ptr(p) {}

? ? T* operator&() { return ptr; }

? ? const T* operator&() const { return ptr; }

};

?

?

3. 代理模式

?

class AddressProxy

{

? ? int* realTarget;

public:

? ? AddressProxy(int* target) : realTarget(target) {}

? ? int** operator&() { return &realTarget; } // 返回指針的地址

? ? const int* const* operator&() const

? ? ?{ return &realTarget; }

};

?

?

重要注意事項

?

1.?謹慎重載:除非有充分理由,否則不要重載取地址運算符

2.?保持一致性:const和非const版本應保持邏輯一致

3.?避免混淆:重載行為應與常規預期相符,避免造成困惑

4.?STL兼容性:某些STL實現可能依賴標準取地址行為

?

實際應用示例

?

安全指針包裝器

?

class SafePointer

{

? ? void* ptr;

public:

? ? SafePointer(void* p) : ptr(p) {}

? ??

? ? // 普通版本

? ? void** operator&()

? ? {

? ? ? ? static int guard;

? ? ? ? if(!ptr) return reinterpret_cast<void**>(&guard);

? ? ? ? return &ptr;

? ? }

? ??

? ? // const版本

? ? const void* const* operator&() const

? ? {

? ? ? ? return const_cast<const void* const*>(&ptr);

? ? }

};

?

?

最佳實踐

?

1.?僅在特殊需求時重載取地址運算符

2.?確保重載后的行為有明確文檔說明

3.?考慮提供?addressof()?成員函數作為替代方案

4.?保持const和非const版本的邏輯一致性

5.?注意線程安全性問題

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80251.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80251.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80251.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HarmonyOS Grid 網格列表可長按 item 拖動移動位置

方案一 @Component struct WorkCircleCreatePage {// 存儲車控列表的數組@State VehicleDoorArr: IVehicleDoor[] = []// 當前移動的Item索引@State CurrentIndex: number = -1// 拖動時顯示的數據@State MoveItem: IVehicleDoor = { title: , icon: }// 拖動時放大倍數@State…

海量數據筆試題--Top K 高頻詞匯統計

問題描述&#xff1a; 假設你有一個非常大的文本文件&#xff08;例如&#xff0c;100GB&#xff09;&#xff0c;文件內容是按行存儲的單詞&#xff08;或其他字符串&#xff0c;如 URL、搜索查詢詞等&#xff09;&#xff0c;單詞之間可能由空格或換行符分隔。由于文件巨大&…

【數據結構】Map與Set結構詳解

數據結構系列五&#xff1a;Map與Set(一) 一、接口的實現 1.方法上 2.成員上 二、Map的內外雙接口結構 1.實現 1.1外部Map接口的實現 1.1.1臨摹整體 1.1.2外部類實現整體 1.2內部Entry接口的實現 1.2.1臨摹內部 1.2.2內部類實現內部 2.關系 3.意義 3.1邏輯內聚 …

Electron使用WebAssembly實現CRC-32 原理校驗

Electron使用WebAssembly實現CRC-32 原理校驗 將C/C語言代碼&#xff0c;經由WebAssembly編譯為庫函數&#xff0c;可以在JS語言環境進行調用。這里介紹在Electron工具環境使用WebAssembly調用CRC-32 原理格式校驗的方式。 CRC-32 原理校驗函數WebAssembly源文件 C語言實現C…

【晶振】晶振的工作原理及其與單片機關系

晶振(晶體振蕩器)是電子設備中常見的元件,其核心功能是提供穩定的時鐘信號,而單片機(MCU)依賴這一信號來同步內部操作。以下是晶振的工作原理及其與單片機關系的詳細說明: 一、晶振的工作原理 壓電效應與諧振 晶振的核心是石英晶體,利用其壓電效應: 當在晶體兩端施加電…

【Oracle專欄】函數中SQL拼接參數 報錯處理

Oracle相關文檔,希望互相學習,共同進步 風123456789~-CSDN博客 1.背景 最近同事反饋了一個很奇怪的問題,即有一個函數,入參是當前年月,主要作用是通過SQL語句將不合規的數據插入到指定表中,插入數據時帶上入參的年月參數。當前問題:單獨測試SQL沒有問題可以執行成功,…

nodejs之Express-介紹、路由

五、Express 1、express 介紹 express 是一個基于 Node.js 平臺的極簡、靈活的 WEB 應用開發框架,官方網址: https://www.expressjs.com.cn/ 簡單來說,express 是一個封裝好的工具包,封裝了很多功能,便于我們開發 WEB 應用(HTTP 服務) (1)基本使用 第一步:初始化項目并…

Unicode和 ASCII碼以及UTF-8編碼的區別和聯系

Unicode、ASCII 和 UTF-8 是計算機編碼領域的關鍵概念&#xff0c;它們既有聯系又有區別。以下是它們的對比分析&#xff1a; 1. ASCII&#xff08;美國信息交換標準碼&#xff09; 誕生時間&#xff1a;1967 年&#xff08;7 位編碼&#xff0c;共 128 字符&#xff09;。特點…

STM32F103_HAL庫+寄存器學習筆記20 - CAN發送中斷+ringbuffer + CAN空閑接收中斷+接收所有CAN報文+ringbuffer

導言 如上所示&#xff0c;在[[STM32F103_HAL庫寄存器學習筆記19 - CAN發送中斷CAN接收中斷接收所有CAN報文ringbuffer數據結構]]的基礎上&#xff0c;為CAN發送端也引入了ringbuffer&#xff08;環形緩沖區&#xff09;機制。CAN發送有三個發送郵箱&#xff0c;為什么還另外需…

Windows 環境下安裝 MariaDB 及 HeidiSQL 使用教程

引言 本報告旨在提供一份詳盡的操作指南。內容將覆蓋在 Windows 操作系統上安裝 MariaDB Community Server 的全過程。我們還將探討如何利用 HeidiSQL 這款圖形用戶界面&#xff08;GUI&#xff09;工具&#xff0c;直觀地預覽和管理我們新安裝的數據庫。除了安裝與配置的步驟…

美團2024年春招第一場筆試 C++

目錄 1&#xff0c;小美的平衡矩陣 2&#xff0c;小美的數組詢問 3&#xff0c;小美的MT 4&#xff0c;小美的朋友關系 1&#xff0c;小美的平衡矩陣 【題目描述】 給定一個n*n的矩陣&#xff0c;該矩陣只包含數字0和1。對于 每個i(1<i<n)&#xff0c;求在該矩陣中&am…

09-DevOps-Jenkins實現CI持續集成

前面已經把harbor搭建好了&#xff0c;也可以向harbor中推送自定義鏡像。 原計劃是在Jenkins這臺服務器上&#xff0c;完成鏡像構建&#xff0c;然后把鏡像推送的harbor倉庫中。現在改變計劃了&#xff0c;Jenkins所在的服務器&#xff08;192.168.1.10&#xff09;不負責鏡像…

Postman設置了Cookies但是請求不攜帶Cookie

1 問題說明 使用Postman工具往往要向本地服務器發送請求攜帶Cookie便于測試接口&#xff0c;但是在Send下面的Cookies選項中設置域名127.0.0.1&#xff0c;并添加Cookie&#xff0c;發現發送的請求怎么都不會攜帶Cookie&#xff1a; 通過Fiddler抓包發現并沒有Cookie&#xff1…

【unity】Vulkan模式下部分Android機型使用VideoPlayer組件播放視頻異常問題

一、問題背景 考慮到Vulkan高性能的優勢&#xff0c;項目組決定打包設置為vulkan優先&#xff0c;opengl es次之的方案&#xff1b;但由于部分低端設備或者部分模擬器對Vulkan的兼容性良莠不齊&#xff0c;導致諸如使用VideoPlayer組件無法正常播放視頻等問題頻發&#xff0c;而…

0802api設計和實戰-網絡ajax請求1-react-仿低代碼平臺項目

文章目錄 1 API設計1.1 用戶功能1.1.1 獲取用戶信息1.1.2 注冊1.1.3 登錄 1.2 問卷功能1.2.1 獲取單個問卷1.2.2 獲取問卷列表1.2.3 創建問卷1.2.4 更新問卷1.2.5 批量徹底刪除問卷1.2.6 復制問卷 1.3 小結 2 實戰2.1配置axios2.2 封裝API和測試2.3 新建問卷2.4 自定義hooks封裝…

Android Kotlin AIDL 完整實現與優化指南

本文將詳細介紹如何在Android中使用Kotlin實現AIDL&#xff08;Android Interface Definition Language&#xff09;&#xff0c;并提供多種優化方案。 一、基礎實現 1. 創建AIDL文件 在src/main/aidl/com/example/myapplication/目錄下創建&#xff1a; IMyAidlInterface.…

【數據結構】_棧和隊列相關面試題

&#x1f525; 數據結構修煉場 &#x1f525; &#x1f4a5; 棧與隊列 終極試煉 &#x1f4a5; &#x1f680; 理論已加載完畢&#xff0c;代碼之魂覺醒時刻&#xff01; ?? 是時候用實戰點燃你的算法之力了—— 「題目風暴&#xff0c;來襲&#xff01;」 &#xff08;握…

精益數據分析(8/126):從Airbnb案例看精益創業與數據驅動增長

精益數據分析&#xff08;8/126&#xff09;&#xff1a;從Airbnb案例看精益創業與數據驅動增長 大家好&#xff01;一直以來&#xff0c;我都堅信在創業和技術的領域里&#xff0c;持續學習與分享是不斷進步的關鍵。今天&#xff0c;咱們繼續深入學習《精益數據分析》&#x…

專題二十:路由策略與策略路由

一、路由策略 1.1 路由策略的概念 路由策略是通過修改路由表的路由條目來控制數據流量的可達性。即對接受和發布的路由進過濾。這種方式稱為路由策略 路由策略功能相關作用控制路由的發布可通過路由策略對所要發布的路由信息進行過濾&#xff0c;只允許發布滿足條件的路由信…

VSCode 擴展離線下載方法

學習自該文章&#xff0c;感謝作者&#xff01; 2025 年 VSCode 插件離線下載攻略&#xff1a;官方渠道一鍵獲取 - 知乎 獲取擴展關鍵信息 方法一&#xff1a;官網獲取 打開 VSCode 擴展官方網站 搜索要下載的擴展&#xff0c;以 CodeGeeX 為例&#xff0c;網址為&#xf…