在 C 面向对象编程中赋值操作是对象间数据传递的核心行为而 ** 浅赋值浅拷贝与深赋值深拷贝是处理对象成员尤其是指针成员的两种核心机制。二者的核心区别在于是否为指针成员分配独立的内存空间错误使用浅赋值会导致内存泄漏、重复释放、数据污染等严重问题。本文将从概念、原理、代码示例、应用场景四个维度彻底讲清浅赋值与深赋值的区别与实践。一、基础概念什么是赋值操作C 中当使用运算符将一个对象赋值给另一个同类型对象时会调用拷贝赋值运算符。若我们不手动定义编译器会自动生成一个默认拷贝赋值运算符这是浅赋值的源头浅赋值与深赋值本质是拷贝赋值运算符对对象成员的两种不同处理方式。二、浅赋值浅拷贝1. 核心定义浅赋值是逐字节拷贝对象的成员变量对于普通成员int、char 等直接拷贝值对于指针成员仅拷贝指针存储的内存地址不拷贝指针指向的实际数据。2. 核心特点两个对象的指针成员指向同一块内存空间操作简单编译器自动生成的默认赋值运算符就是浅赋值致命缺陷修改一个对象的指针数据另一个对象会同步变化对象销毁时同一块内存会被重复释放导致程序崩溃。3. 代码示例浅赋值的问题#include iostream #include cstring using namespace std; // 测试类包含指针成员 class Student { public: char* name; // 指针成员核心风险点 int age; // 构造函数为指针分配内存 Student(const char* n, int a) { age a; // 为name指针分配堆内存 name new char[strlen(n) 1]; strcpy(name, n); } // 析构函数释放指针内存 ~Student() { // 浅赋值下同一块内存会被释放两次 delete[] name; cout 对象已销毁内存释放成功 endl; } }; int main() { Student s1(张三, 20); Student s2(李四, 18); // 编译器自动生成的默认赋值运算符 → 浅赋值 s2 s1; // 问题1修改s1的names2的name同步变化指向同一块内存 strcpy(s1.name, 王五); cout s1姓名 s1.name endl; // 输出王五 cout s2姓名 s2.name endl; // 输出王五预期应为张三 // 问题2程序结束时s1和s2的析构函数会重复释放同一块内存 → 程序崩溃 return 0; }4. 浅赋值适用场景仅当类中没有指针、引用等动态分配的成员变量时浅赋值完全安全如仅包含 int、double、普通数组的类。三、深赋值深拷贝1. 核心定义深赋值是手动重载拷贝赋值运算符对于指针成员先分配一块独立的新内存再将原指针指向的数据拷贝到新内存中。最终两个对象的指针成员指向不同的内存空间。2. 核心特点两个对象拥有独立的指针数据互不干扰避免内存重复释放、数据污染问题需要手动编写拷贝赋值运算符不能依赖编译器默认实现。3. 代码示例深赋值解决问题#include iostream #include cstring using namespace std; class Student { public: char* name; int age; // 构造函数 Student(const char* n, int a) { age a; name new char[strlen(n) 1]; strcpy(name, n); } // 析构函数 ~Student() { delete[] name; cout 对象已销毁内存释放成功 endl; } // 【关键】手动重载拷贝赋值运算符 → 实现深赋值 Student operator(const Student s) { // 1. 防止自赋值如 s1 s1 if (this s) { return *this; } // 2. 释放当前对象原有的指针内存避免内存泄漏 delete[] this-name; // 3. 分配新内存拷贝数据深赋值核心步骤 this-age s.age; this-name new char[strlen(s.name) 1]; strcpy(this-name, s.name); // 4. 返回当前对象支持连续赋值s1 s2 s3 return *this; } }; int main() { Student s1(张三, 20); Student s2(李四, 18); // 调用重载的赋值运算符 → 深赋值 s2 s1; // 验证修改s1的数据s2不受影响 strcpy(s1.name, 王五); cout s1姓名 s1.name endl; // 输出王五 cout s2姓名 s2.name endl; // 输出张三符合预期 // 程序结束两个对象的指针指向不同内存分别释放无崩溃 return 0; }4. 深赋值核心步骤必记重载拷贝赋值运算符时必须遵循 4 步标准流程判断自赋值避免自己释放自己的内存释放原有内存防止当前对象的指针内存泄漏分配新内存 拷贝数据实现真正的深赋值返回当前对象引用支持连续赋值语法。四、浅赋值 vs 深赋值核心对比表表格特性浅赋值浅拷贝深赋值深拷贝实现方式编译器自动生成无需手动编写必须手动重载拷贝赋值运算符指针成员处理仅拷贝内存地址共享数据分配新内存拷贝数据独立存储数据安全性低易出现数据污染、重复释放高对象数据完全独立内存开销小稍大需要分配独立内存适用场景无指针 / 动态内存的类包含指针、动态数组、字符串的类五、关键总结编译器默认的赋值都是浅赋值只要类中有指针成员、动态分配内存new/malloc必须手动实现深赋值浅赋值的核心风险指针共享内存导致数据篡改、内存重复释放深赋值的核心逻辑为指针分配独立内存拷贝实际数据从根源解决浅赋值问题面向对象编程中遵循三法则如果类需要手动实现析构函数、拷贝构造函数、拷贝赋值运算符中的任意一个通常三个都需要手动实现核心都是为了处理深拷贝。总结浅赋值逐字节拷贝指针共享内存仅适用于无动态成员的类深赋值手动重载赋值运算符指针独立分配内存解决动态内存安全问题含指针 / 动态内存的类禁止使用编译器默认浅赋值必须实现深赋值。