引用 &
-
使用引用
int b = 33, &a = b; b = 17; cout << a; // 打印a为17
使用引用声明变量类似于指针,声明的变量会同被引用的变量绑定,修改任何一方的数据都会使另一方的数据也改变。使用上的区别在于使用引用不需要
*
,引用可以理解为一个别名。 -
在函数中使用引用传递参数
将参数设置为引用的作用是:调用函数时参数不进行拷贝,而是直接使用传入的变量,在函数中的所有修改都会应用于该变量。
-
基本类型
int myAge = 15; void newYear(int &age){age++;}
使用引用传递变量,调用函数
newYear(myAge)
,myAge
变量将会被改变 -
复杂数据结构(如类,结构体)
vector<int> v(100); void sum(vector<int> &v){/* 求和 */}
函数参数的传递都是拷贝一份副本,将副本传递进去(如基本类型),所以如果不使用引用,程序将会复制整个vector,大大浪费了时间以及内存
-
指针
引用跟指针的功能很类似,都是为了能在函数中修改传入的参数。
相同点:下面代码中调用函数后m变量存储的都是demo的地址,m中的height也都被修改了
void setHeight(member &m, int height){m.height = height;} setHeight(demo, h); void setHeight(member *m, int height){m->height = height;} setHeight(&demo, h);
不同点:
-
对于引用形式,虽然m变量存储的是被引用对象的地址,但对程序员来讲,m就是作为demo的一个别名,使用m就等于使用demo,而不是使用demo的地址。
-
对于指针,假如以下面形式调用函数:
member *p = &demo; setHeight(p, h);
传入变量p作为参数后,p与m的值都是
&demo
,即p和m都指向demo的地址,使用他们都能修改demo中的数据,但他们是两个不同的变量,即&p
与&m
是不同的,在函数中修改m变量并不能作用于p变量。本质上,传递指针参数也是拷贝变量。对于下面代码:
void applyForMemory(node *n){ n = new node[10]; } node *p; applyForMemory(p);
这段代码是不起作用的,n申请了空间,只是将n指向的地址改成了新空间的地址,但p的指向没有改变。这段代码反而造成了内存泄漏。
void applyForMemory(node *&n){ n = new node[10]; } node *p; applyForMemory(p);
将指针作为引用形式传递,可理解为变量n即p。给n申请了空间,n的指向被修改了,p也被修改。
总而言之,单纯传递指针参数实际上是存在两个变量:作为参数传入的变量(p)和在函数中使用的变量(n),他们的值都是同一个地址,他们指向同一个地方(demo),所以能够在函数中使用n变量来修改demo变量的数据;但他们还是两个变量,具有不同的地址,在函数中修改n的值(即修改n的指向)并不能作用与p,p的指向依旧是demo。
而将指针作为引用来传递可以简单理解为只有一个变量:p,把n当作p的别名,那么修改了n的值(指向)自然p的指向也被修改了;当然,实际上n与p还是两个变量,p存储着demo的地址,而n中存储的是p的地址,编译器会自动将对n的操作转换成对p的操作,所以看起来他们就是同一个变量。
-
-
-
函数返回值使用引用
将返回值的引用返回,即不进行复制然后返回副本
当然,如果使用引用作为返回值,那么是无法返回在函数中声明的变量的。因为那些变量在栈中,随着函数的结束运行,栈的内存被释放,该变量也会被释放。
node* & AVLTree::getRoot(){return this->root;} node* & root = tree.getRoot();