【C++入门】Cyber骇客构造器的核心六元组 —— 【类的默认成员函数】明明没写构造函数也能跑?保姆级带你掌握六大类的默认成员函数(上:函数篇)

⚡ CYBER_PROFILE ⚡
/// SYSTEM READY ///


WARNING \]: DETECTING HIGH ENERGY **🌊 🌉 🌊 心手合一 · 水到渠成** ![分隔符](https://i-blog.csdnimg.cn/direct/60a3de2294e9439abad47378e657b337.gif) |------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------| | **\>\>\> 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对象取地址 注释:这两个很少会自己实现 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/61878482825243f29feb058a34a94c80.png) *** ** * ** *** ### 构造函数 **构造函数是特殊的成员函数** 需要注意的是,构造函数虽然名字叫**构造**,但其主要任务并不是开空间创建对象(我们常使用的局部对象在栈帧创建时,空间就已经开好了),而是在对象实例化时初始化对象。 构造函数的本质是为了替代我们以前在 `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()` **输出:** ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d5db4f11353c420b94403ff18af6bd1f.png) *** ** * ** *** #### 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; } ``` ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7b58c1591da74ec7a76c0a00f45d2bb4.png) *** ** * ** *** #### 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 } ``` ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a3540f2b00574aa8b83af019f5a14cf8.png) *** ** * ** *** ### 拷贝构造函数 如果一个构造函数的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数叫做拷贝构造函数 也就是说,**拷贝构造函数是一个特殊的构造函数** #### 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; } ``` ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5272f53fce874de2bb1a51744b46657d.png) *** ** * ** *** ##### 引用返回 返回的是对象的别名,没有拷贝,效率高 ```cpp // 场景:返回静态变量(生命周期贯穿整个程序) Date& TestByRef() { static Date d(2025); // 静态变量,出了函数不销毁 return d; // 返回 d 的别名,没有拷贝 } int main() { cout << "--- 开始调用 TestByRef ---" << endl; Date& ret = TestByRef(); // ret 也是引用,直接指向静态区的 d cout << "--- 调用结束 ---" << endl; return 0; } ``` ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/8b4c3a7bd83c4853b3378ec260dc5678.png) *** ** * ** *** ##### ❌ 错误用法示例 **返回局部变量的引用** ```cpp Date& BadRef() { Date d(2026); return d; // 警告:函数结束,d 的栈帧销毁,d 的内存被系统回收 } int main() { Date& ret = BadRef(); // 此时 ret 指向的是一块已经被释放的内存(野引用) // 这里的打印可能是随机值,或者程序直接崩溃 cout << ret._year << endl; return 0; } ``` *** ** * ** *** > **下一章节我们将详细讲讲默认成员函数中的运算符重载💪** *** ** * ** *** ## 💻结尾--- 核心连接协议 **警告:** 🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠 *** ** * ** *** **【📡】 建立深度链接:** **关注**本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。 **【⚡】 能量过载分发:** 执行**点赞**操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。 **【💾】 离线缓存核心:** 将本页加入**收藏**。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。 **【💬】 协议加密解密:** 在**评论区**留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。 **【🛰️】 信号频率投票:** 通过**投票**发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。 *** ** * ** *** ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/57b03915c54b43a7a03fa92dbbfe57c3.gif) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0905dc972de8414bb602715de3f866ee.gif)

相关推荐
代码无bug抓狂人2 小时前
C语言之切蛋糕(运用前缀和算法和单调队列算法)
c语言·开发语言
漫漫求2 小时前
Go的panic、defer、recover的关系
开发语言·后端·golang
Tony Bai2 小时前
2025 Go 官方调查解读:91% 满意度背后的隐忧与 AI 时代的“双刃剑”
开发语言·后端·golang
沐知全栈开发2 小时前
R 绘图 - 饼图
开发语言
charlie1145141912 小时前
嵌入式C++开发——RAII 在驱动 / 外设管理中的应用
开发语言·c++·笔记·嵌入式开发·工程实践
Fcy6482 小时前
C++11 新增特性(中)
开发语言·c++·c++11·可变参数模版·c++11 类的新增功能·c++11slt新增特性
恒者走天下2 小时前
计算机想学习某个方向,怎么知道学习路线
c++
小码过河.2 小时前
17装饰器模式
开发语言·python·装饰器模式
嫂子开门我是_我哥2 小时前
第八节:条件判断与循环:解锁Python的逻辑控制能力
开发语言·python