引用

函数返回引用

使用引用作为函数的返回值,效率更高,但是需要注意,返回引用需要保证对象存在,不允许返回局部变量的引用
下面是一个函数返回引用的例子:
在使用链表构建堆栈的过程中,返回栈顶元素的函数可以返回引用,因为栈顶元素还在。

1
2
3
T& top_element(){
return lst.back();
}

但是pop函数就不能返回引用了,因为在弹出栈之后,该元素作为局部变量已经消失,因此不能返回引用,只能退而求其次,返回对象的值(返回一个拷贝)。

1
2
3
4
5
T pop(){
T el = lst.back();
lst.pop_back();
return el;
}

运算符重载返回引用

运算符重载使用对象的引用作为返回值,主要是从如下两个方面进行考虑:

  1. 减少创建临时对象的开销(和函数返回引用原因相同)
  2. 允许进行链式操作

例如现在有一个Mystring类,为了进行赋值操作,类中对赋值操作符进行了重载:

1
2
3
4
5
6
7
8
9
Mystring& Mystring::operator=(const Mystring& rhs){
if(this == &rhs)
return *this;

delete [] str;
str = new char[std::strlen(rhs.str) + 1];
std::strcpy(str,rhs.str);
return *this;
}

可以看到,函数内部已经对被赋值的对象进行了修改,为什么还要返回对象的引用呢?返回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进行赋值,就没有任何问题。不返回对象引用而返回对象本身也没有问题,但是会重复调用多次构造函数和析构函数,导致性能下降。##

引用与指针的区别

初学引用时,可能会与指针混淆,在此处总结二者区别:

  1. 指针是一个变量,引用是一个对象的别名;(你在学校叫张含韵,在家叫二丫子)
  2. 指针大小为4字节(32位)或8字节(64位),引用大小为对象大小
  3. 指针可以为null,引用必须初始化
  4. 指针修改对象需要解引用,而修改引用会直接修改变量
  5. 指针可以指向别的对象(花心),引用只能是一个对象的引用(专一)
  6. 指针可以有多级,引用没有
  7. 指针++和引用++含义不同
  8. 返回动态内存分配的对象必须返回指针
0%