1、
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
形参变量的改变要影响实参–指针或者引用
#includeusing namespace std; // C++标准库的东西 int main() { int a = 10; int& b = a; return 0; }
2、
#includeusing namespace std; // C++标准库的东西 int main() { int a = 10; int& b = a; int& c = a; int& d = b; c = 20; d = 30; return 0; }
3、
以前交换写法
#includeusing namespace std; // C++标准库的东西 void Swap(int* p1, int* p2) { int tmp = *p1; *p1 = *p2; *p2 = tmp; } int main() { int x = 0, y = 1; Swap(&x, &y); }
现在–使用引用的写法
void Swap(int& rx, int& ry)
{
int tmp = rx;
rx = ry;
ry = tmp;
}
int main()
{
int x = 0, y = 1;
Swap(x, y);
}
栈初始化以前的写法
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
void StackInit(ST* ps)
{
ps->a = NULL;
ps->top = ps->capacity = 0;
}
int main()
{
ST st;
StackInit(&st);
return 0;
}
栈初始化–使用引用后的写法
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
void StackInit(ST& rs)
{
rs.a = NULL;
rs.top = rs.capacity = 0;
}
int main()
{
int x = 0, y = 1;
Swap(&x, &y);
Swap(x, y);
ST st;
StackInit(st);
SListNode* plist = NULL;
SListPushBack(plist, 1);
SListPushBack(plist, 2);
return 0;
}
单链表对引用的使用
typedef struct SListNode
{
struct SListNode* next;
int val;
}SLTNode, *PSLTNode;
//void SListPushBack(PSLTNode& phead, int x)---不推荐这种写法,PSLTNode是结构图的指针
void SListPushBack(SLTNode*& phead, int x)
{
SLTNode* newnode;
if (phead == NULL)
{
phead = newnode;
}
else
{
//...
}
}
int main()
{
SListNode* plist = NULL;
SListPushBack(plist, 1);
SListPushBack(plist, 2);
return 0;
}
4、指针变量取别名
int main()
{
int x = 0, y = 1;
int* p1 = &x;
int* p2 = &y;
int*& p3 = p1; // 指针变量取别名
*p3 = 10;
p3 = p2;
}
5、const和引用
- 我变成你的别名的条件:不变或者缩小的你的读写权限是可以的,放大你的读写权限不行的
int main()
{
const int a = 10;
int& b = a; // 变成你的别名,还能修改你 (不行)
int c = 20;
const int& d = c; // 变成你的别名,不修改你 (行)
}
- 别名可以改变,但是不是每个别名都和原名字有一样的权限(d只是别名,但不能修改)
引用转换的过程
int main()
{
int i = 10;
double d = i;
const double& r = i;
char ch = 0xff;
int j = 0xff;
int k = ch;
// ch就会提升转换成int类型,再比较,提升时部位符号位
// 这里把ch提升,你把ch变成一个int吗?,是生成一个临时变量int
if (ch == j)
{
cout << "相同" << endl;
}
else
{
cout << "不相同" << endl;
}
return 0;
}
6、 const的好处
typedef struct Stack
{
int a[1000];
int top;
int capacity;
}ST;
void StackInit(ST& s) // 这里传引用是为了形参的改变,影响实参
{
s.top = 0;
s.capacity = 1000;
// ...
}
void PrintStack(const ST& s)
// 1、传引用是为了减少传值传参时的拷贝
// 2、可以保护形参形参不会被改变
{
// 假设有这样一个逻辑 -> 如果时const引用,这里就可以被检查出来
//if (s.capacity = 0) // 本来应该是== ,不小心写成=
{
}
}
void func(const int& n) // const引用做参数的第二个好处,即可接收变量,也可以接收常量
{
}
int main()
{
ST st;
StackInit(st);
// ...
PrintStack(st);
int i = 10;
const int j = 30;
func(i);
func(20);
func(j);
return 0;
}
- 好处1
void PrintStack(const ST& s)
加引用 – void PrintStack(const ST& s) 本来就不需要指针,但是使用引用减少传值传参时的拷贝
加const – 可以保护形参形参不会被改变,万一写成if(s.capacity=0){}的时候会改变形参
-
好处2
const引用做参数的第二个好处,即可接收变量,也可以接收常量 -
总结
函数传参如果想减少拷贝用了引用传参,如果函数中不改变这个参数, 最好用const 引用传参
7、 引用做返回值
传值返回
int Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
传值返回
int Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
const int& ret = Add(1, 2);//临时变量具有常性,所以需要加const才行
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
引用返回
- 取别名返回,没有返回值,有可能带来越界访问且结果不确定因为栈帧销毁了–C的值是随机的
- vs上没清理栈帧,结果为3
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);//ret为c的别名
//Add(3, 4);
printf("hello worldn");
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
- 再在ret加一层引用–vs上也出错了
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
//Add(3, 4);
printf("hello worldn");
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
总结:什么时候用引用
测试引用 – 理解
测一次测不出来
#includestruct A { int a[10000]; }; void TestFunc1(A a){} void TestFunc2(A& a){} void TestRefAndValue() { A a; // 以值作为函数参数 size_t begin1 = clock(); TestFunc1(a); size_t end1 = clock(); // 以引用作为函数参数 size_t begin2 = clock(); TestFunc2(a); size_t end2 = clock(); // 分别计算两个函数运行结束后的时间 cout << "TestFunc1(A)-time:" << end1 - begin1 << endl; cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl; }
cpu太快了
重复一万次,一万次传字节和一万次引用
#includestruct A { int a[10000]; }; void TestFunc1(A a){} void TestFunc2(A& a){} void TestRefAndValue() { A a; // 以值作为函数参数 size_t begin1 = clock(); for (size_t i = 0; i < 10000; ++i) TestFunc1(a); size_t end1 = clock(); // 以引用作为函数参数 size_t begin2 = clock(); for (size_t i = 0; i < 10000; ++i) TestFunc2(a); size_t end2 = clock(); // 分别计算两个函数运行结束后的时间 cout << "TestFunc1(A)-time:" << end1 - begin1 << endl; cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl; }
8、引用和指针
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 30;
return 0;
}
- 理解性看就行



