旨在理解指针和引用的区别
Persona("张三");Person*p=&a;//指针Person&r=a;//引用定义方式
• 指针:Person* p,p 是独立变量,存对象的地址,p 自己有内存。
• 引用:Person& r = a,r 仅仅是对象 a 的别名,引用本身不占用独立内存(编译器层面,逻辑上没有独立实体)。
• 引用定义的时候必须初始化绑定对象,不能先声明后赋值。
Person&r;//❌编译报错,引用必须初始化Person*p;//✅指针可以先定义,后面再赋值 p=&a能不能改变指向(绑定目标)
• 指针:可以!p = &b;,让指针指向另一个对象。
• 引用:一旦绑定,永远不能换绑定对象。
注意:r = b;不是改变引用绑定,等价a = b,是赋值给原对象 a。
Persona("a"),b("b");Person&r=a;r=b;//❗不是r绑定b!把b拷贝赋值给a,r依旧是a的别名。是否可以为 NULL / 空
• 指针:Person* p = nullptr; ✅允许,可以是空。
• 引用:不允许为空,引用一定绑定一个有效对象。
• 工程上:引用天然保证不为空;指针要时刻判断nullptr。
使用语法
• 指针:解引用p,访问成员p->setName()
• 引用:直接像对象一样用,r.setName(),不需要、->
const 修饰的行为(重点)
const Person* p; //指针:指向const对象,指针可改指向
Person* const p; //指针本身const,不能改指向
//引用没有“普通引用const”这种写法
Person& const r = a; // ❌语法非法!引用天生不能改绑定,加const无意义。
实测vs2015编译可以通过,但是报warning C4227: 使用了记时错误: 忽略引用上的限定符,好像标准c++缺少不允许这么写。msvc微软编译器的兼容扩展,跨平台不能这么写。本身没有意义。
const Person& r = a; // ✅const引用:被引用的对象只读
sizeof 结果
• sizeof§:得到指针本身大小(x64 为 8 字节)。
• sizeof®:得到原对象 Person 的大小,不是引用大小。
引用逻辑上没有独立内存,sizeof 看的是它绑定的实体。
拷贝行为
Person* p1 = &a;
Person* p2 = p1; //拷贝指针的值(地址),两个指针指向同一个a
Person& r1 = a;
Person& r2 = r1; //r2也是a的别名,没有拷贝对象
没有构造,没有拷贝构造,没有拷贝赋值运算。
函数参数场景对比
//指针,有可能传入nullptr,函数内部要判空
void funcPtr(Person* p) { if(nullptr == p) return; p->print(); }
//引用,一定是有效对象,不需要判空
void funcRef(Person& r) { r.print(); }
| 对比项 | 指针 Person* p | 引用 Person& r |
|---|---|---|
| 初始化 | 可以先定义,后赋值 | 定义时必须绑定对象 |
| 能否为空 | nullptr 合法 | 绝不允许为空 |
| 能否改变指向目标 | ✅p=&b可以修改指向 | ❌绑定后永远不能更换目标 |
| 语法访问对象 | *p,p->xxx | 直接 r.xxx |
| sizeof | 得到指针本身大小 (8 字节 x64) | 得到原始对象大小 |
| const 语法 | const Person* / Person* const两种 | 只有const Person&,Person& const非法 |
| 内存 | 指针变量自己占内存 | 逻辑上只是别名,无独立内存 |
| 传参 | 需要考虑判空 | 一定有效,无需判空 |