一、值传递
函数调用时传递对象,会调用拷贝构造函数(可能是浅拷贝或深拷贝,取决于类如何定义)
二、引用传递
函数调用时传递对象的引用,不调用拷贝构造函数,直接对原值进行操作
三、指针传递
将原指针复制一份传递给函数,本质也属于值传递,在函数内部可以修改副本指针指向的地址(不影响原指针的指向),或者可以用*解引用来直接修改原地址的值。
四、三种传递方法的示例和总结
#include <stdio.h>
//此函数需要在C++中运行,C语言中没有引用传递,在C语言中此函数会报错,在C语言可以用指针传递代替引用传递
int setValue(int& a,int b){ // 变量a是引用传递,直接对原始变量进行操作,变量b是值传递,会拷贝原变量b生成副本
a=3; // 修改的是原变量
b=6; // 修改的是局部副本
return a+b; // 返回 3+6=9
}
int setValue2(int* a,int b){ // 变量a是指针传递,会拷贝原变量的地址,变量b是值传递,会拷贝原变量f生成副本
printf("局部变量a的值:%p\n",a);//可以发现a的值就是原变量的地址
*a=3; // 通过解引用修改地址中的值,等同于修改的是原变量
b=6; // 修改的是局部副本
return *a+b; // 返回 3+6=9
}
int main(){
//对比引用传递和值传递
int a=5;
int b=5;
int c = setValue(a,b);
printf("a:%d, b:%d, c:%d\n",a,b,c);//可以发现a被修改了,但是b未被修改
//对比指针传递和值传递
int e=5;
int f=5;
int g = setValue2(&e,f);
printf("原变量e的地址:%p\n",&e);
printf("e:%d, f:%d, g:%d\n",e,f,g);//可以发现e被修改了,但是f未被修改
}

| 特性 | 值传递 | 指针传递 | 引用传递 |
|---|---|---|---|
| 语言支持 | C/C++ | C/C++ | C++特有 |
| 传递内容 | 变量的副本 | 变量的地址 | 变量的别名 |
| 修改原值 | 不可能 | 可以(需解引用) | 可以直接修改 |
| 内存开销 | 复制整个数据 | 固定大小(指针大小) | 通常无额外开销 |
| 空值安全 | 总是安全 | 需要检查空指针 | 必须绑定有效对象 |
五、浅拷贝
默认的拷贝构造函数(只复制指针,不复制指针指向的数据)
六、深拷贝
自定义拷贝构造函数(复制指针指向的数据)
七、两种拷贝方式示例
#include <iostream>
#include <cstring>
using namespace std;
class Person {
private:
int age;
public:
char* name; // 动态分配的姓名
// 构造函数
Person(const char* name, int age) : age(age) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
std::cout << "构造函数: " << name << std::endl;
}
// 浅拷贝构造函数(危险!)
Person(const Person& other) : name(other.name), age(other.age) {
std::cout << "浅拷贝构造函数: " << name << std::endl;
}
// 析构函数
~Person() {
std::cout << "析构函数: " << name << std::endl;
delete[] name;
}
void print() const {
std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
}
void setName(const char* newName) {
strcpy(name, newName);
}
};
class Person2 {
private:
int age;
public:
char* name; // 动态分配的姓名
// 构造函数
Person2(const char* name, int age) : age(age) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
std::cout << "构造函数: " << name << std::endl;
}
//深拷贝构造函数(安全)
Person2(const Person2& other) : age(other.age) {
name = new char[strlen(other.name) + 1];
strcpy(name, other.name);
std::cout << "深拷贝构造函数: " << name << std::endl;
}
// 析构函数
~Person2() {
std::cout << "析构函数: " << name << std::endl;
delete[] name;
}
void print() const {
std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
}
void setName(const char* newName) {
strcpy(name, newName);
}
};
// 值传递函数
void passByValue1(Person p) {
std::cout << "值传递内部: ";
p.print();
p.setName("内部修改");
}
// 值传递函数
void passByValue2(Person2 p) {
std::cout << "值传递内部: ";
p.print();
p.setName("内部修改");
}
// 引用传递函数
void passByReference1(Person& p) {
std::cout << "引用传递内部: ";
p.print();
p.setName("内部修改");
}
// 引用传递函数
void passByReference2(Person2& p) {
std::cout << "引用传递内部: ";
p.print();
p.setName("内部修改");
}
int main() {
std::cout << "\n=== 引用传递 (高效安全) ===" << std::endl;
{
Person charlie("Charlie", 35);
passByReference1(charlie); // 引用传递,不拷贝
std::cout << "引用传递后原始对象: ";
charlie.print(); // 原始对象被修改
} // 正常析构
std::cout << "\n=== 深拷贝 + 值传递 (安全示例) ===" << std::endl;
{
// 使用深拷贝构造函数的情况
Person2 bob("Bob", 30);
passByValue2(bob); // 值传递触发深拷贝
std::cout << "bob.name指针值: " << static_cast<void*>(bob.name) << std::endl;
std::cout << "值传递后原始对象: ";
bob.print(); // 原始对象不受影响
} // 正常析构,没有内存问题
std::cout << "=== 浅拷贝 + 值传递 (危险示例) ===" << std::endl;
{
Person alice("Alice", 25);
passByValue1(alice); // 值传递触发浅拷贝
std::cout << "引用传递后原始对象: ";
alice.print(); // 原始对象被修改
//这里会导致双重释放错误!因为在passByValue中采用浅拷贝构造了对象p,p的name指针和alice的name指针指向同一块内存,而在passByValue函数运行结束p对象被释放,此刻alice的name指针就变成了悬空指针
//而在出代码块alice会调用析构导致alice.name双重释放,此时可能出现乱码,原因:析构函数尝试读取已释放内存的内容,读到的是一些随机数据(内存垃圾)
}
return 0;
}

1368

被折叠的 条评论
为什么被折叠?



