1.方便链式调用
如果一个"="的操作符重载写成如下:

void operator=(const Myclass& oth)
{
    this->value = oth.value;
}

那么如下是不对的:

Myclass a, b, c;
c = b = a;

当然你也会想,我写成值类型赋值不就好了:

Myclass operator=(const Myclass& oth)
{
    this->value  = oth.value;
    return *this;
}
Myclass a, b, c;
c = b = a;

这样当然编译和运行当然没问题,但是链式赋值时会产生很多的临时对象,如果Myclass对象含有的数据量很大的时候(比如很多复杂的成员变量或者其他类的对象),复制一个对象消耗的时间就会比较大,如果改成引用的话,就会少一份拷贝,return的时候不会产生临时对象:

Myclass& operator=(const Myclass& oth)
{
    this->value = oth.value;
    return *this;
}

 

其实还有一个非常经典的应用就是:std::string a,b,c; std::cout<<a<<b<<c<<std::endl; cout其实是一个操作流类的对象,其伪代码实现大意如下:

ostream &operator<<(ostream &os,const std::string &str)
{
    .....
    return os;
}

正因为返回了一个流对象引用,所以才能std::cout<<a<<b<<std::endl;一直输出下去,不然如果返回值为void,那只能如下输出:

std::cout << a;
std::cout << b;
std::cout << std::endl;

返回为值赋值的话,那也会产生拷贝。
但是注意的是我们千万不要返回局部变量的引用
 
 
2.返回类成员变量的引用
2.1返回常成员变量的引用  
当你可能需要某个类里面的成员变量的时候,如这个矩阵类里的单位矩阵变量,又如下:
复制于 C++ 中引用有什么用? - 谢之易的回答 - 知乎 https://www.zhihu.com/question/34267829/answer/58414818
图片说明
为了仅仅只是想用变量的值,不想在类外的代码会改变变量,最好返回值为const &
 
 
2.2返回类的普通成员的引用
这些成员可能本身是某些private/protected字段的一部分,但在符合条件时允许外部直接修改,容器类当中很常见。如std::vector、std::map等STL容器的operator[],不返回引用,无法修改a[x]的值,为了同时支持a[x]的取值即v=a[x]和a[x]=v的赋值两种操作,就需要a[x]返回一个左值,用指针的话你得解引用才能成为一个左值表达式,不直观至于其他情况很多时候改用指针也不算很不方便。比如std::vector,伪代码实现的思路一般如下:

template<class T> 
T& vector<T>::operator [] (const size_type & n)
{
    ...
}

如果你的实现为:

template<class T> 
void vector<T>::operator [](const size_type & n){

...//直接修改

}

那么a[x]只能当一个左值,只能写不能读,无法实现v=a[x],因为a[x]的返回值是一个void。