在 C 中class类对象的传值和传引用是两种截然不同的参数传递方式它们在性能、内存管理和行为上有着本质的区别。简单来说传值是“复制一份”传引用是“取个别名”。以下是详细的对比分析1. 核心区别概览表格特性传值传引用 ()机制创建对象的副本(拷贝)对象的别名(直接操作原对象)修改影响函数内修改不影响外部对象函数内修改直接影响外部对象性能开销高(需调用拷贝构造函数)低(无拷贝仅传递地址)内存占用占用双倍内存 (原对象副本)几乎不占额外内存安全性高 (外部数据受保护)较低 (外部数据可能被意外修改)多态性会导致对象切片(丢失派生类信息)支持多态(保留完整信息)2. 深入解析 传值当你按值传递一个类对象时C 会调用该类的拷贝构造函数来创建一个完全独立的副本。优点数据安全函数内部无论怎么折腾都不会影响原始数据。语义清晰适合传递小型对象或不需要修改的场景。缺点性能差如果类很大包含大量成员变量或动态内存拷贝操作非常耗时。对象切片如果传递的是派生类对象给基类形参派生类特有的部分会被“切掉”导致多态失效。 传引用传递引用实际上是传递对象的内存地址但在语法上看起来像直接操作变量。优点高性能没有拷贝开销无论对象多大传递效率都一样高。支持多态可以传递派生类对象给基类引用正确调用虚函数。修改原值允许函数直接修改调用者的数据如果需要的话。缺点副作用风险如果不小心可能会意外修改外部数据。3. 代码示例12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include iostream#include string#include vectorclassStudent {public:std::string name;intage;Student(std::string n,inta) : name(n), age(a) {}// 拷贝构造函数用于演示传值时的拷贝行为Student(constStudent other) : name(other.name), age(other.age) {std::cout [拷贝构造函数被调用] std::endl;}};// --- 1. 传值 ---// 这里的 s 是 originalStudent 的副本voidmodifyByValue(Student s) {s.name Modified_Value;s.age 99;std::cout 函数内(值): s.name , s.age std::endl;}// --- 2. 传引用 (非常用) ---// 这里的 s 是 originalStudent 的别名voidmodifyByReference(Student s) {s.name Modified_Reference;s.age 88;std::cout 函数内(引用): s.name , s.age std::endl;}// --- 3. 常量引用 (最佳实践) ---// 既避免了拷贝又防止了修改voidprintStudent(constStudent s) {// s.name Error; // 编译错误不能修改 const 对象std::cout 函数内(只读): s.name , s.age std::endl;}intmain() {Student originalStudent(Alice, 20);std::cout 原始数据: originalStudent.name , originalStudent.age std::endl;std::cout --- 调用传值函数 --- std::endl;modifyByValue(originalStudent);// originalStudent 未被修改但触发了拷贝构造std::cout 调用后: originalStudent.name , originalStudent.age std::endl std::endl;std::cout --- 调用传引用函数 --- std::endl;modifyByReference(originalStudent);// originalStudent 被修改了std::cout 调用后: originalStudent.name , originalStudent.age std::endl;return0;}4. 什么时候用哪个最佳实践在实际开发中请遵循以下规则首选const引用 (const ClassName obj)场景绝大多数情况。当你只需要读取对象数据不需要修改它时。理由避免了昂贵的拷贝开销同时保证了数据安全不会被函数修改。例子void printData(const std::vectorint data);次选非const引用 (ClassName obj)场景当你需要在函数内部修改对象状态时。理由高效且意图明确调用者知道数据会被改。例子void updateConfig(Config cfg);最后传值 (ClassName obj)场景对象非常小如只包含 1-2 个int的类。你确实需要一个副本并且要在函数内随意修改而不影响原对象。注意对于像std::vector、std::string或大型自定义类永远不要按值传递。