[原创]C++基础系列—左值引用

有没有想过一个问题,为什么C++ 有了指针( Pointer),仍然引进 “引用(Reference)” 这个概念?C++之父的解释:

C++ inherited pointers from C, so I couldn’t remove them without causing serious compatibility problems. References are useful for several things, but the direct reason I introduced them in C++ was to support operator overloading (简译: C++ 为了兼容 C,所以不可能会移除指针;引用在很多地方有用处,但主要是为了解决运算符重载 )

operator overloading (运算符重载)

运算符重载为什么必须要用到引用呢?我们看看下面一个实例,你就能理解为什么需要引用

#include <iostream>
using namespace std;

class Box
{
public:
    int length;
    Box(int len){ length = len; }

    //值方式重载
    Box operator+=(const Box b)
    {
        Box box(0);
        box.length = this->length + b.length;
        return box;
    }

    //引用方式重载
    Box& operator+=(const Box& b)
    {
        this->length = this->length + b.length;
        return *this;
    }

    //指针方式重载
    Box* operator+=(const Box* b)
    {
        this->length = this->length + b->length;
        return this;
    }
};

Box GetBox() { return Box(1); }

int main()
{
    Box box(1);
    //值方式重载示例
    (box += box) += box; //result:1
    //引用方式重载示例
    (box += box) += box;//result:4
    //指针方式重载示例
    *(box += &box) += &box;//result:4
    //只有引用方式的重载才能正确编译
    box += GetBox();
    cout << "box.Length = " << box.length << endl;
    return 0;
}

值方式重载有两个问题:

  • 构造函数被调用多次;浪费性能
  • 功能未实现;(box += box) += box 结果不符合预期

指针方式重载也有以下两个问题:

  • 写法不够简洁,晦涩难懂
  • box += GetBox() 编译不过(不能用 “右值” 当实参)

函数参数

C++ 之父说还说,引用在有些地方也很有用。除了重载运算符,作为函数参数也很有用,示例如下:

void Func(Foo foo);//有拷贝构造,不推荐
void FuncPtr(Foo* foo);//无拷贝构造,但是foo使用之前需判空
void FuncRef(const Foo& foo);//无拷贝构造,官方推荐(可传入右值实参)

你是不是以为就这了?其实它还有个隐藏的用处,请看以下代码:

void foo(const int& value)
{
    int temp = value + 1;
}

void bar(const int* value)
{
    int temp = *value + 1;
}

int main()
{
    int value = 1;
    int& ref = value;
    int* ptr = &value;

    foo(2);
    foo(value);
    foo(ref);

    bar(2);      //error
    bar(value);  //error
    bar(ptr);    //error
    return 0;
}

函数 foo(const int& value) 可以接受三种实参, 这一点在模板里面很有用 ;而 bar(const int* value) 只能接受指针类型实参

函数返回值

还有没有其它用处呢?我觉得写单例的时候会用到。以下是 C++ 单例的 “标准” 写法:

class Singleton 
{
 private:
    Singleton (void)

 public:
    static Singleton& getInstance()
    {
        static CSingleton m_pInstance;
        return m_pInstance;
    }
};

为什么引用的单例比指针的更好?因为安全,返回的是引用不可被更改,而且不会为空

总结

综上,引用的作用有以下地方:

  • operator overloading;不仅是为了简化语法,还是为了实现功能
  • 作为函数形参
  • 作为函数返回值

当然,我们这里讨论的都是普通引用,也就是左值引用;C++ 11以后引入了右值引用,初看很迷惑,实际也是为了解决问题,下一篇我们再来谈谈