+号运算符重载与引用的关系

文章部分内容参考知乎用户 黄昏 的一篇文章。感谢♥ ♥
该文章地址:https://zhuanlan.zhihu.com/p/...

左值引用的定义

我们在程序中常用的引用为左值引用(右值引用是C++11新增的特性,在此不进行讨论)。首先来看左值引用:

int a = 10;  
int &b = a; // 定义一个左值引用向量
b = 100;    // 通过左值引用来修改引用内存的值

引用的本质为一个指针常量,那么int &b = a 其实为:int* const b = &a。明白了这一点,我们就能理解以下代码无法编译通过的原因。

int &b = 10; 

这是因为10无法进行取地址操作,也就是无法对立即数取地址(这是因为立即数存储在寄存器中,而不是内存里)。但是,我们就想引用常量数字10该怎么办呢?我们可以使用常引用:

const int &b = 10;

上面这句代码是可以编译通过的。因为当我们使用常引用来引用常量数字10时,此时内存上产生了临时变量,而临时变量是可以取地址的。相当于:

const int temp = 10;  // temp为临时变量
const int &b = temp;

总结一下:
左值引用要求右边的值必须取得地址。如果无法取得地址,就需要使用常引用。但使用常引用后,只能通过引用读取数据,而无法修改数据。

加号运算符重载

定义一个student类,student.h文件如下:

#pragma once
#include

using namespace std;

class student
{
    friend ostream& operator<<(ostream& cout, const student& stu);  /* 
                                                                     *左移运算符重载,请注意这里的第二个形 
                                                                     *参,为何加了const?仅仅因为防止对象内容                                                                      *被修改?
                                                                     */

public:
    student(int, int);
    student(const student&);  // 同样的,自定义的拷贝构造函数为何也加了const?
    ~student();
    student operator+(const student& stu);  /*
                                             *文章标题为重载+号运算符和引用的关系。因此,下面将首先讲解这里加
                                             *const的原因,随后引出上面两个疑问的答案。
                                             */
    
private:
    int* mPWeight;
    int* mPHeight;
};

student.cpp文件:

#include "student.h"

student::student(int weight, int height)
{
    mPWeight = new int(weight);
    mPHeight = new int(height);
}

student::student( const student& stu)
{
    mPWeight = new int(*stu.mPWeight);
    mPHeight = new int(*stu.mPHeight);
}

student student::operator+(const student& stu)
{
    student temp(*mPWeight + *stu.mPWeight, *mPHeight + *stu.mPHeight);
    return temp;
}

student::~student()
{
    if (mPWeight != NULL)
    {
        delete mPWeight;
        mPWeight = NULL;
    }

    if (mPHeight != NULL)
    {
        delete mPHeight;
        mPHeight = NULL;
    }
}

main.cpp文件:

#include"student.h"

ostream& operator<<(ostream& cout, const student& stu) 
{
    cout << *(stu.mPWeight) << " " << *(stu.mPHeight);
    return cout;
}

int main()
{
    student student1(120, 180);

    student student2(110,170);

    student student3 = student1 + student2;
    
    cout << student1 + student2;

    return 0;
}

在解答student.h中的两个疑问之前,我们还要了解左值和右值的含义。在C++中左值和右值没有标准的定义,但以下说法是得到普遍认可的:

 可取地址的,有名字的,非临时的为左值;
 不可取地址的,没名字的,临时的为右值。

那么,立即数、函数返回的值、匿名对象为右值(这点太重要了,是本篇文章的精髓),非匿名对象(包含变量)、函数返回的引用。

再来看student.cpp中的+号重载函数,返回了一个值!!!那么再来看main.cpp中的 student student3 = student1 + student2;,这行代码的运行过程为:student1 + student2返回一个匿名对象(为方便起见,我们用temp代表该匿名对象);再调用student类的拷贝构造函数,此时:const student& stu = temp。看到这里,应该明白了叭。假如为:student& stu = temp;,temp是右值,无法取地址,也就无法使用左值引用。需要加const来构成常量引用(移步第一部分:左值引用的定义)。这样才可以编译通过。所以拷贝构造函数的形参加const的原因远远不止于:防止传入的对象内容被更改。 所以我们在写拷贝构造函数时,必须要加const。

<<重载函数的疑问也就随之解开了。

你可能感兴趣的:(visual-studio,c++,运算符重载,引用)