The only me is me, but are you sure the only you is you?
引用
函数返回引用
使用引用作为函数的返回值,效率更高,但是需要注意,返回引用需要保证对象存在,不允许返回局部变量的引用。
下面是一个函数返回引用的例子:
在使用链表构建堆栈的过程中,返回栈顶元素的函数可以返回引用,因为栈顶元素还在。
1 | T& top_element(){ |
但是pop函数就不能返回引用了,因为在弹出栈之后,该元素作为局部变量已经消失,因此不能返回引用,只能退而求其次,返回对象的值(返回一个拷贝)。
1 | T pop(){ |
运算符重载返回引用
运算符重载使用对象的引用作为返回值,主要是从如下两个方面进行考虑:
- 减少创建临时对象的开销(和函数返回引用原因相同)
- 允许进行链式操作
例如现在有一个Mystring类,为了进行赋值操作,类中对赋值操作符进行了重载:
1 | Mystring& Mystring::operator=(const Mystring& rhs){ |
可以看到,函数内部已经对被赋值的对象进行了修改,为什么还要返回对象的引用呢?返回void不可以么?返回void的问题是会导致链式赋值失效,当然如果不进行链式赋值,返回void也是可以的。
关于链式赋值失效,还需要从赋值语句的值谈起,赋值语句的值是赋值对象的值。
1 | a=b=c; |
上面的语句可以视为如下语句:
1 | a=(b=c); |
b=c
这条语句的值就是c,或者说是被赋值之后的b,然后再用这条语句的值,为a赋值。而如果重载的赋值语句返回void,那么造成的结果是b=c
这条语句返回值为void,利用void给a进行赋值,会导致类型不匹配的问题,所以为了使链式赋值生效,b=c
必须返回c的值,或者被赋值之后的b的值,此时给a进行赋值,就没有任何问题。不返回对象引用而返回对象本身也没有问题,但是会重复调用多次构造函数和析构函数,导致性能下降。##
引用与指针的区别
初学引用时,可能会与指针混淆,在此处总结二者区别:
- 指针是一个变量,引用是一个对象的别名;(你在学校叫张含韵,在家叫二丫子)
- 指针大小为4字节(32位)或8字节(64位),引用大小为对象大小
- 指针可以为null,引用必须初始化
- 指针修改对象需要解引用,而修改引用会直接修改变量
- 指针可以指向别的对象(花心),引用只能是一个对象的引用(专一)
- 指针可以有多级,引用没有
- 指针++和引用++含义不同
- 返回动态内存分配的对象必须返回指针