⚡ CYBER_PROFILE ⚡
/// SYSTEM READY ///
WARNING \]: DETECTING HIGH ENERGY
**🌊 🌉 🌊 心手合一 · 水到渠成**

|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| **\>\>\> ACCESS TERMINAL \<\<\<** ||
| [**\[ 🦾 作者主页 \]**](https://blog.csdn.net/fengtinghuqu520?spm=1000.2115.3001.5343) | [**\[ 🔥 C语言核心 \]**](https://blog.csdn.net/fengtinghuqu520/category_12955956.html) |
| [**\[ 💾 编程百度 \]**](https://blog.csdn.net/fengtinghuqu520/category_13083835.html) | [**\[ 📡 代码仓库 \]**](https://blog.csdn.net/fengtinghuqu520/article/details/147275999?spm=1001.2014.3001.5502) |
---------------------------------------
Running Process: 100% \| Latency: 0ms
*** ** * ** ***
#### 索引与导读
* [为什么会有 默认成员函数 ?](#为什么会有 默认成员函数 ?)
* [六大默认成员函数](#六大默认成员函数)
*
* [构造函数](#构造函数)
*
* [1. 函数名与类名相同](#1. 函数名与类名相同)
* [2. 无返回值(也不写 void)](#2. 无返回值(也不写 void))
* [3. 实例化时自动调用](#3. 实例化时自动调用)
* [4. 可以重载(可以有多个)](#4. 可以重载(可以有多个))
* [5. 编译器默认生成](#5. 编译器默认生成)
* [6. 默认构造函数的"三合一"与歧义](#6. 默认构造函数的“三合一”与歧义)
*
* [C++ 规则](#C++ 规则)
* [7. 内置类型 vs 自定义类型](#7. 内置类型 vs 自定义类型)
* [析构函数](#析构函数)
*
* [1. 命名规则](#1. 命名规则)
* [2. 一个类只能有一个构造函数](#2. 一个类只能有一个构造函数)
* [3. 对象生命周期结束时自动调用](#3. 对象生命周期结束时自动调用)
* [4. 默认生成的析构函数](#4. 默认生成的析构函数)
* [5. 显式写的析构函数](#5. 显式写的析构函数)
* [6. 资源申请与资源泄露](#6. 资源申请与资源泄露)
* [7. 析构顺序:后定义的先析构](#7. 析构顺序:后定义的先析构)
* [拷贝构造函数](#拷贝构造函数)
*
* [1. 声明形式](#1. 声明形式)
* [2. 拷贝构造函数的触发时机](#2. 拷贝构造函数的触发时机)
*
* [2.1)对象初始化](#2.1)对象初始化)
* [2.2)对象作为参数传递](#2.2)对象作为参数传递)
* [2.3)对象作为返回值](#2.3)对象作为返回值)
* [3. 浅拷贝 vs 深拷贝](#3. 浅拷贝 vs 深拷贝)
*
* [典例代码演示](#典例代码演示)
* [浅拷贝](#浅拷贝)
* [深拷贝](#深拷贝)
*
* [为什么要手写 深拷贝构造函数 ?](#为什么要手写 深拷贝构造函数 ?)
*
* [❗ 崩溃代码示例](#❗ 崩溃代码示例)
* [4. 传值返回 vs 引用返回](#4. 传值返回 vs 引用返回)
*
* [传值返回](#传值返回)
* [引用返回](#引用返回)
* [❌ 错误用法示例](#❌ 错误用法示例)
* [💻结尾--- 核心连接协议](#💻结尾— 核心连接协议)
## 为什么会有 默认成员函数 ?
在 `C++` 中,当你定义一个"空类"时,它并不是真正的空。
**编译器会为你自动生成一套默认成员函数**
## 六大默认成员函数
为了演示,我们假设全篇代码都包含以下头文件:
```cpp
#include
#include //用于 strlen, strcpy
#include // 用于 swap
using namespace std; // 全局引入命名空间
```
* **重点:** 前 `4` 个 *(构造、析构、拷贝构造、赋值重载)* 是最重要的,必须熟练掌握。
* **次要:** 后 `2` 个 *(取地址重载)* 通常不需要理会
C++ 6个默认成员函数
功能分类
初始化和清理
拷贝复制
取地址重载
构造函数
主要完成初始化工作
析构函数
主要完成清理工作
拷贝构造函数
使用同类对象初始化创建对象
赋值运算符重载
把一个对象赋值给另一个对象
取地址运算符重载
普通对象取地址
取地址运算符重载
const对象取地址
注释:这两个很少会自己实现

*** ** * ** ***
### 构造函数
**构造函数是特殊的成员函数**
需要注意的是,构造函数虽然名字叫**构造**,但其主要任务并不是开空间创建对象(我们常使用的局部对象在栈帧创建时,空间就已经开好了),而是在对象实例化时初始化对象。
构造函数的本质是为了替代我们以前在 `Stack` 和 `Date` 类中编写的 `Init` 函数的功能;构造函数自动调用的特点完美地替代了 `Init` ,从而避免了忘记初始化带来的风险。
```cpp
class ClassName {
public:
ClassName(); // 构造函数声明
};
ClassName::ClassName() {
// 构造函数定义
}
```
#### 1. 函数名与类名相同
```cpp
//函数名与类名相同
class Date {
public:
Date() {}
private:
int _year;
int _month;
int _day;
};
```
*** ** * ** ***
#### 2. 无返回值(也不写 void)
```cpp
class Date {
public:
//无返回值
Date() {}
private:
int _year;
int _month;
int _day;
};
```
*** ** * ** ***
#### 3. 实例化时自动调用
```cpp
#include
using namespace std;
//函数名与类名相同
class Date {
public:
//无返回值
Date() {}
Date(int year, int month, int day) {
_year = year;
_month = month;
_day = day;
cout << "-> 自动调用了带参构造函数" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main() {
cout << "1. 准备创建 d1:" << endl;
Date d1; //实例化 d1 ,自动调用无参构造
cout << "2. 准备创建 d2:" << endl;
Date d2(2025, 1, 22); // 实例化 d2,自动调用带参构造
return 0;
}
```
*** ** * ** ***
#### 4. 可以重载(可以有多个)
```cpp
#include
using namespace std;
class Date {
public:
// 【特点1 & 2】: 函数名是Date,前面没有 void,也没有返回值
// 【特点4】: 这是第一个构造函数(无参)
Date() {
_year = 1900;
_month = 1;
_day = 1;
// 【特点3】: 只要对象创建,这句话就会打印,证明它被自动调用了
cout << "-> 自动调用了无参构造函数" << endl;
}
// 【特点4】: 这是第二个构造函数(带参),体现了函数重载
Date(int year, int month, int day) {
_year = year;
_month = month;
_day = day;
cout << "-> 自动调用了带参构造函数" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main() {
cout << "1. 准备创建 d1:" << endl;
Date d1; // 实例化 d1,自动调用无参构造
cout << "2. 准备创建 d2:" << endl;
Date d2(2025, 1, 22); // 实例化 d2,自动调用带参构造
return 0;
}
```
*** ** * ** ***
#### 5. 编译器默认生成
如果类中没有显式定义,编译器生成默认的;一旦用户定义了,编译器就不再生成
```cpp
class A {
// 里面什么都没写
// 编译器会生成一个 A() { ... }
};
class B {
public:
// 用户显式定义了一个带参构造
B(int x) {
cout << "B的构造" << endl;
}
// 此时,编译器不再生成无参的 B()
};
int main() {
A a; // ✅ 编译通过:调用了编译器自动生成的默认构造
// B b; // ❌ 编译报错!
// 错误原因:类 B 中已经有了一个 B(int),编译器就不送你 B() 了。
// 你必须要么手动写一个 B(),要么像下面这样传参:
B b(10); // ✅ 编译通过
return 0;
}
```
*** ** * ** ***
#### 6. 默认构造函数的"三合一"与歧义
**无参构造、全缺省构造、编译器** 生成的构造,都叫"**默认构造函数**"(不用传参就能调用的)
**但它们只能存在一个,否则会有歧义**
```cpp
#include
using namespace std;
class Date {
public:
// 1. 无参构造函数
Date() {
cout << "无参构造" << endl;
}
// 2. 全缺省构造函数
// 理论上它也是"默认构造函数",因为可以不传参调用
Date(int year = 1, int month = 1, int day = 1) {
cout << "全缺省构造" << endl;
}
};
int main() {
Date d;
return 0;
}
```
**❌ 编译报错**
编译器懵了:*你是指调用第1个不需要参数的?还是调用第2个使用默认参数的?*
##### C++ 规则
* 一个类只能有一个"默认构造函数"
* "默认构造函数"指:可以不传递任何参数就能调用的构造函数
* 当类中同时存在**无参构造函数** 和**全缺省构造函数**时,编译器无法区分该调用哪一个
*** ** * ** ***
#### 7. 内置类型 vs 自定义类型
**编译器默认生成的构造函数:**
* **对内置类型(`int`, `char`, `指针`):** 不处理(值是随机的)。
* **对自定义类型(`class`, `struct`):** 自动调用那个成员的默认构造函数
```cpp
#include
using namespace std;
// 自定义类型
class Stack {
public:
Stack() {
cout << "Stack 的构造函数被调用了(初始化栈)" << endl;
_capacity = 4; // 假设初始化容量
}
private:
int _capacity;
};
// 包含两种成员的类
class MyQueue {
public:
// ❌ 我们这里故意不写构造函数
// 测试编译器默认生成的构造函数会做什么
void Print() {
cout << "内置类型 _size 的值: " << _size << endl;
cout << "内置类型 _ptr 的值: " << _ptr << endl;
}
private:
// 1. 内置类型
int _size;
int* _ptr;
// 2. 自定义类型
Stack _st;
};
int main() {
MyQueue q;
// 观察结果:
// 1. Stack 的构造函数会被打印出来 -> 证明自定义类型被处理了。
// 2. _size 和 _ptr 的值通常是乱码(随机值) -> 证明内置类型没被处理。
q.Print();
return 0;
}
```
**A. 对内置类型(int_size, int\*_ptr)**
* **行为**: 不做处理(或者说初始化是不确定的,看编译器)。
* **结果**: 这就是为什么你在 Print() 函数中看到的是随机值(乱码)。编译器只是分配了内存,但没有往里面填入具体的 0 或 nullptr。
**B. 对自定义类型(Stack_st)**
* **行为**: 要求调用这个成员变量的默认构造函数初始化。
* **结果**: 编译器生成的 MyQueue 构造函数内部会隐式调用 Stack()。这就是为什么你的屏幕上会打印出 "Stack 的构造函数被调用了"。
*** ** * ** ***
### 析构函数
🚩析构函数与构造函数功能相反
析构函数不是完成对对象本身的销毁,比如局部对象是存在`栈帧`的,函数结束`栈帧`销毁,它就释放了,不需要我们管,**`C++`规定对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作**
> 析构函数的功能 **类比** 我们之前`Stack`实现`Destroy`功能,而像`Date`没有`Destroy`,其实就是没有资源需要释放,**所以严格说`Date`是不需要析构函数的**
#### 1. 命名规则
* **知识点:** 析构函数名是在类名前加上字符 `~`
* **解析:** `~(取反符号)`在逻辑上暗示了它与构造函数(创建)相反的操作(销毁)
* **补充:** 它是类的成员函数,且名称必须与类名完全一致
```cpp
class Student {
public:
// 构造函数
Student() {
cout << "构造函数被调用" << endl;
}
~Student() {
cout << "析构函数被调用" << endl;
}
};
```
*** ** * ** ***
#### 2. 一个类只能有一个构造函数
**注意:** 一个类只能有一个析构函数
若未显式定义,系统会自动生成默认的
```cpp
class MyClass {
public:
~MyClass() {
// 合法的析构函数
}
// [错误示范]
// 析构函数不支持重载,因为它没有参数,编译器无法区分
// ~MyClass(int a) { } // 编译报错:destructor cannot have any parameters
};
```
**解析:** 构造函数可以有多个(重载),但因为析构函数没有参数,所以无法重载,只能存在一个。如果你不写,编译器会在后台默默生成一个空的 `~MyClass() {}`
*** ** * ** ***
#### 3. 对象生命周期结束时自动调用
```cpp
#include
using namespace std;
class Test {
public:
~Test() {
cout << "对象正在被销毁..." << endl;
}
};
int main() {
cout << "主函数开始" << endl;
{ // 创建一个局部作用域
Test t;
cout << "对象 t 在作用域内活着" << endl;
} // [重点] 出了这个右大括号,t 的生命周期结束,系统自动调用 ~Test()
cout << "主函数结束" << endl;
return 0;
}
```
**输出结果:**
1. 主函数开始
2. 对象 t 在作用域内活着
3. 对象正在被销毁... (自动调用)
4. 主函数结束
*** ** * ** ***
#### 4. 默认生成的析构函数
对**内置类型(如 int)**不做处理,对**自定义类型成员**会调用它的析构
```cpp
#include
using namespace std;
// 自定义类型
class Custom {
public:
Custom() { cout << "Custom构造" << endl; }
~Custom() { cout << "Custom析构" << endl; }
};
// 测试类
class Test {
public:
Test() { cout << "Test构造" << endl; }
~Test() { cout << "Test析构" << endl; }
// 析构函数结束后,编译器自动处理成员:
// - 对内置类型(int,指针等):什么都不做
// - 对自定义类型(custom):自动调用其析构函数
private:
int num; // 内置类型 - 析构时什么也不做
Custom obj; // 自定义类型 - 自动调用~Custom()
};
int main() {
Test t; // 构造
return 0;
}
```
**t离开作用域,调用\~Test():**
1. 执行析构函数体(打印"`Test` 析构")
2. 编译器自动处理成员:
* `num`: 什么都不做
* `obj`: 自动调用`~Custom()`
**输出:**

*** ** * ** ***
#### 5. 显式写的析构函数
即使你手动写了**析构函数**,函数体执行完后,自定义类型成员的析构函数依然会被自动调用
```cpp
#include
using namespace std;
class Member {
public:
~Member() {
cout << "Member析构" << endl;
}
};
class MyClass {
public:
MyClass() {
cout << "MyClass构造" << endl;
}
// 手动写的析构函数
~MyClass() {
cout << "MyClass析构函数体开始" << endl;
// 做一些清理工作...
cout << "MyClass析构函数体结束" << endl;
// 函数体执行完后,编译器会自动调用所有自定义类型成员的析构函数
}
private:
Member m; // 自定义类型成员
};
int main() {
MyClass obj;
return 0;
}
```

*** ** * ** ***
#### 6. 资源申请与资源泄露
* **无资源申请** (如 `Date`):可不写析构,用默认的
```cpp
class Date {
private:
int year;
int month;
int day;
// 成员全是内置类型,且没有动态申请内存(new/malloc)
// 使用编译器默认生成的析构函数即可,什么都不用做
};
```
* **有资源申请** (如 `Stack`):必须写析构释放资源,否则内存泄漏
```cpp
#include
class Stack {
private:
int* _array; // 指针,指向堆内存
int _capacity;
int _top;
public:
Stack(int capacity = 4) {
_capacity = capacity;
// [资源申请] 在堆上动态开辟了空间
_array = new int[capacity];
}
// [重点 7] 必须显式写析构函数来释放资源
~Stack() {
if (_array) {
delete[] _array; // 归还操作系统内存
_array = nullptr;
std::cout << "Stack 内存已释放,防止泄漏" << std::endl;
}
}
};
```
**解析:** 如果 `Stack` 类不写析构函数,默认析构函数只会销毁 `_array` 这个指针变量本身(占据`8`字节),而指针指向的那一大块堆内存(比如 `100MB`)将永远无法释放,造成内存泄漏
*** ** * ** ***
#### 7. 析构顺序:后定义的先析构
**知识点回顾:** 局部域的多个对象,C++ 规定后定义的先析构` (栈的特性:先进后出)`
```cpp
#include
using namespace std;
class Object {
int _id;
public:
Object(int id) : _id(id) {
cout << "对象 " << _id << " 被构造" << endl;
}
~Object() {
cout << "对象 " << _id << " 被析构" << endl;
}
};
int main() {
// 构造顺序:1 -> 2
Object o1(1);
Object o2(2);
return 0;
// [重点 8] 析构顺序将是:2 -> 1
}
```

*** ** * ** ***
### 拷贝构造函数
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数叫做拷贝构造函数
也就是说,**拷贝构造函数是一个特殊的构造函数**
#### 1. 声明形式
```cpp
class ClassName {
public:
// 拷贝构造函数的声明
ClassName(const ClassName& other);
};
```
1. **同名构造**:函数名必须与类名完全一致。
2. **引用传递(必须)** :参数必须是该类类型的引用(通常是 `ClassName&`)。
* **为什么不能传值?** 如果传值(`ClassName other`),为了将实参传给形参,系统会再次调用拷贝构造函数,从而导致无限递归,直到栈溢出。
3. **常量限定(建议)** :通常使用 `const` 修饰。
* **原因** :这保证了在拷贝过程中不会意外修改源对象,同时也允许拷贝 `const` 对象(即右值或常量对象)
*** ** * ** ***
#### 2. 拷贝构造函数的触发时机
在以下三种情况下,编译器会自动调用拷贝构造函数:
##### 2.1)对象初始化
用一个对象去定义并初始化另一个对象
```cpp
Person p1;
Person p2 = p1; // 调用拷贝构造
Person p3(p1); // 调用拷贝构造
```
##### 2.2)对象作为参数传递
函数参数是对象而非引用时
```cpp
void func(Person p) { ... }
```
##### 2.3)对象作为返回值
函数返回一个局部对象
```cpp
Person func() {
Person temp;
return temp; // 返回时调用
}
```
*** ** * ** ***
#### 3. 浅拷贝 vs 深拷贝
##### 典例代码演示
```cpp
#include
using namespace std;
class Date {
public:
// 1. 普通构造函数:申请堆内存
Date(int year = 1900) {
_yearPtr = new int(year); // 在堆区开辟空间存储 year
cout << "【构造】申请内存地址: " << _yearPtr << " 值: " << *_yearPtr << endl;
}
// 2. 深拷贝构造函数
Date(const Date& d) {
// 核心区别:
// 浅拷贝写法: _yearPtr = d._yearPtr; (两个指针指向同一块内存,危险!)
// 深拷贝写法: 重新申请一块新的内存
_yearPtr = new int(*d._yearPtr);
cout << "【深拷贝】申请新内存地址: " << _yearPtr << " (原地址: " << d._yearPtr << ")" << endl;
}
// 3. 析构函数:释放内存
~Date() {
if (_yearPtr != nullptr) {
cout << "【析构】释放内存地址: " << _yearPtr << endl;
delete _yearPtr;
_yearPtr = nullptr;
}
}
// 用于打印查看
void print() {
cout << "当前年份: " << *_yearPtr << endl;
}
// 成员变量改为指针
int* _yearPtr;
};
int main() {
cout << "--- 创建对象 d1 ---" << endl;
Date d1(2025);
cout << "\n--- 创建对象 d2 (深拷贝 d1) ---" << endl;
Date d2(d1); // 调用深拷贝构造
cout << "\n--- 验证独立性 ---" << endl;
// 修改 d2 的值
*d2._yearPtr = 2099;
cout << "d1 的年份 (应保持 2025): " << *d1._yearPtr << endl;
cout << "d2 的年份 (已改为 2099): " << *d2._yearPtr << endl;
cout << "\n--- 作用域结束,自动析构 ---" << endl;
return 0;
}
```
##### 浅拷贝
如果你没有手动定义拷贝构造函数,编译器会生成一个**默认拷贝构造函数**
*执行**位拷贝**,即简单地复制成员变量的值*
* **风险:** 如果类中包含指针并指向堆内存,浅拷贝会导致两个对象的指针指向同一个内存地址。当对象析构时,同一块内存会被释放两次,导致程序崩溃
```cpp
String(const String& other) {
this->data = other.data; // 仅仅复制了地址!
}
```
使用时机
浅拷贝只复制对象的第一层属性
* 如果属性是**基本类型(如数字、字符串)** ,**拷贝值**
* 如果属性是**引用类型(如对象、数组)** ,**拷贝的是内存地址**(引用)
如果你创建副本只是为了在一个函数内部进行读取、计算,并且保证绝对不会修改内部的可变对象,浅拷贝就足够了
##### 深拷贝
当类中包含指针成员或动态分配的资源时,必须手动编写拷贝构造函数,为新对象分配独立的内存空间,并复制内容
```cpp
class String {
private:
char* data;
public:
// 构造函数
String(const char* str) {
data = new char[strlen(str) + 1];
strcpy(data, str);
}
// 手写深拷贝构造函数
String(const String& other) {
// 1. 为新对象分配独立内存
data = new char[strlen(other.data) + 1];
// 2. 拷贝实际内容
strcpy(data, other.data);
}
~String() { delete[] data; }
};
```
**如果你使用浅拷贝:**
```cpp
String(const String& other) {
data = other.data;
}
```
**❌ 危险!两个指针指向同一块堆内存**
*** ** * ** ***
使用时机
深拷贝会递归地复制对象及其所有子对象,在内存中创建一个完全独立的副本
**场景:** 将一个复杂的表单数据对象传递给"提交"函数,如果提交失败需要回滚,或者用户点击了"取消",你需要原始数据保持原样
*** ** * ** ***
###### 为什么要手写 深拷贝构造函数 ?
如果使用**默认的拷贝构造函数(浅拷贝)** ,系统只会简单地复制**指针**的值,编译器生成的代码逻辑类似于:
```cpp
// 编译器自动生成的默认拷贝构造函数(浅拷贝)
String(const String& other) {
this->data = other.data; // 仅仅复制了地址!
}
```
* **后果 A(数据篡改):** 修改对象 A 的字符串,对象 B 的也跟着变了。
* **后果 B(双重释放崩溃):** 当 A 和 B 析构时,会对同一个地址调用两次 delete\[\],导致程序直接崩溃(Double Free)
*** ** * ** ***
###### ❗ 崩溃代码示例
```cpp
#include
#include
class String {
public:
char* data; // 为了方便演示,暂时设为 public
String(const char* str) {
data = new char[strlen(str) + 1];
strcpy(data, str);
}
// 注意:这里故意删除了手写的深拷贝构造函数,使用系统默认的
~String() {
delete[] data;
std::cout << "析构函数被调用,内存已释放" << std::endl;
}
};
int main() {
{
String s1("Hello");
String s2 = s1; // 触发默认拷贝构造函数(浅拷贝)
std::cout << "s1 地址: " << (void*)s1.data << std::endl;
std::cout << "s2 地址: " << (void*)s2.data << std::endl;
// 此时 s1.data 和 s2.data 指向同一个内存地址
}
// 作用域结束,s1 和 s2 都会调用析构函数
return 0;
}
```
**运行了上面的代码后 发现程序出现了崩溃**
**过程拆解:**
1. **内存重叠** :`s2 = s1` 之后,`s1.data` 和 `s2.data` 保存的是同一个内存地址(例如 `0x1234`)。
2. **第一次释放** :当 `s2` 离开作用域时,析构函数执行 `delete[] data`,地址 `0x1234` 处的内存被回收。
3. **第二次释放(崩溃点)** :紧接着 `s1` 离开作用域,析构函数再次执行 `delete[] data`。由于 `0x1234` 已经被释放过了,再次释放会导致运行时错误。
4. **数据风险** :在析构之前,如果你修改 `s1` 的内容,`s2` 的内容也会莫名其妙地改变,因为它们本质上在看同一块内存。
*** ** * ** ***
> **补充:** `char* strcpy(char* destination, const char* source);`
>
> * 将`source`字符串(包括结尾的 `'\0'`)拷贝到 `destination` 指向的内存中
> 🔗[Lucy的空间骇客裂缝:字符函数与字符串函数](https://blog.csdn.net/fengtinghuqu520/article/details/152969991?spm=1011.2415.3001.10575&sharefrom=mp_manage_link)
*** ** * ** ***
#### 4. 传值返回 vs 引用返回
假设我们要实现一个简单的 `Date` 类:
```cpp
#include
using namespace std;
class Date {
public:
Date(int year = 1900) : _year(year) {
// 普通构造
}
Date(const Date& d) {
_year = d._year;
cout << "【拷贝构造调用】: 生成副本" << endl;
}
~Date() {
// cout << "析构函数调用" << endl;
}
int _year;
};
```
##### 传值返回
* 会产生一个临时对象,调用拷贝构造。
* **缺点:** 对于大对象,拷贝代价大,效率低
```cpp
// 场景:函数内部创建局部对象,并传值返回
Date TestByValue() {
Date d(2024);
return d; // 【重点】:这里会触发拷贝构造,生成临时对象
}
int main() {
cout << "--- 开始调用 TestByValue ---" << endl;
Date ret = TestByValue();
cout << "--- 调用结束 ---" << endl;
return 0;
}
```

*** ** * ** ***
##### 引用返回
返回的是对象的别名,没有拷贝,效率高
```cpp
// 场景:返回静态变量(生命周期贯穿整个程序)
Date& TestByRef() {
static Date d(2025); // 静态变量,出了函数不销毁
return d; // 返回 d 的别名,没有拷贝
}
int main() {
cout << "--- 开始调用 TestByRef ---" << endl;
Date& ret = TestByRef(); // ret 也是引用,直接指向静态区的 d
cout << "--- 调用结束 ---" << endl;
return 0;
}
```

*** ** * ** ***
##### ❌ 错误用法示例
**返回局部变量的引用**
```cpp
Date& BadRef() {
Date d(2026);
return d;
// 警告:函数结束,d 的栈帧销毁,d 的内存被系统回收
}
int main() {
Date& ret = BadRef();
// 此时 ret 指向的是一块已经被释放的内存(野引用)
// 这里的打印可能是随机值,或者程序直接崩溃
cout << ret._year << endl;
return 0;
}
```
*** ** * ** ***
> **下一章节我们将详细讲讲默认成员函数中的运算符重载💪**
*** ** * ** ***
## 💻结尾--- 核心连接协议
**警告:** 🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠
*** ** * ** ***
**【📡】 建立深度链接:** **关注**本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。
**【⚡】 能量过载分发:** 执行**点赞**操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。
**【💾】 离线缓存核心:** 将本页加入**收藏**。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。
**【💬】 协议加密解密:** 在**评论区**留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。
**【🛰️】 信号频率投票:** 通过**投票**发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。
*** ** * ** ***

