有关心情

引用

<!-- index-menu -->

概念

定义:引用是已定义变量的别名。

分类:左值引用(&),右值引用(&&)。

语法:double& lref; | double&& rref;

优点:节省时间和内存。

主要用途:作为参数的形参。引用变量用作参数,函数将使用原始数据,而不是其副本。

示例:

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    double x = 512.0;
    double& r1 = x;
    double& r2 = r1;

    cout << "r1 = " << r1 << endl;
    cout << "r2 = " << r2 << endl;

    cout << &x << " " << &r1 << " " << &r2 << endl;
    return 0;
}

// 输出:
// r1 = 512
// r2 = 512
// 0x61fe90 0x61fe90 0x61fe90  
// 引用变量与被引用变量的地址相同

特点:一生只效忠一个变量。引用必须在声明的时候初始化,类似指针常量:int* const p = num;

示例:

int main()
{
    double num1 = 512;
    double* p = &num1;
    double& r = *p;

    double num2 = 1024;
    p = &num2;

    // 利用以上方式并不能改变引用变量r的指向
    cout << "num1 = " << num1 << endl;
    cout << "r = " << r << endl;
    cout << "*p = " << *p << endl;
    cout << "num2 = " << num2 << endl;
    return 0;
}

// 输出:
// num1 = 512
// r = 512
// *p = 1024
// num2 = 1024

引用传递

引用经常被用作函数参数,这种方式叫作引用传递。

区别于值传递

void swap(int& a, int& b)
{
    a = a + b;
    b = a - b;
    a = a - b;
}

int main()
{
    int a = 512, b = 1024;
    swap(a, b);

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    return 0;
}

// 输出:
// a = 1024
// b = 512

但引用传递的使用是隐晦的:

// 声明
void swap(int a, int b);  // 值传递
void swap(int& a, int& b);  // 引用传递
void swap(int* a, int* b);  // 指针传递

// 定义
...

// 调用
swap(a, b);
swap(a, b);  // 隐晦(与值传递相同)
swap(&a, &b);  // 明显

常量引用

引用容易引起原数据被改变。如果不希望原数据被改变,可考虑值传递或者常量引用

double func(const double& r);

建议:如果基本数值类型,应采用值传递;当数据比较大时(类、结构),考虑引用传递。


一般地,引用参数只接收变量

double func(double& rre)
{
    return rre;
}

int main()
{
    double num = 512;
    double& r = num;
    cout << func(r + 3) << endl;  // (r + 3) 不是变量

    return 0;
}

此时编译器会报错:

error: invalid initialization of non-const reference of type 'double&' from an rvalue of type 'double'

const引用解决了这种尴尬:

double func(const double& rre)
{
    return rre;
}

int main()
{
    double num = 512;
    double& r = num;
    cout << func(r + 3) << endl;

    return 0;
}

// 输出:
// 515

这是因为实参与引用参数不匹配,C++将生成临时变量(在函数调用期间存在),可打印两个变量的地址如下,确定它们并非同一变量。仅当参数为const引用时

cout << &rre << endl;  // 0x61fe88
cout << &r << endl;  // 0x61fe90

出现临时变量的两种情况:

double func(const double& rre)
{
    cout << &rre << endl;
    return rre;
}

int main()
{
    int num = 512;
    int& r = num;
    cout << &r << endl;

    func(r + 3);
    return 0;
}

// 输出:
// 0x61fe8c
// 0x61fe90

左值:常规变量、const变量。

非左值:字面常量(字符串外,因为它们是其地址表示),包含多项的表达式。

const的好处

返回引用

返回引用的函数实际上就是被引用的变量的别名。因此使得以下语句语法正确:

double& func(double& rre)
{
    return rre;
}

int main()
{
    double num = 512;
    func(num) = 1024;  // 语法正确
    cout << "num = " << num << endl;
    return 0;
}

// 输出:
// num = 1024

如果想避免函数结果成为左值,可以加上const:

const double& func(double& rre) {...}

传统返回机制与值传递类似:结果被复制到一个临时位置,调用程序将使用这个值。

double m = sqrt(16.0);  // 值4.0被复制到临时位置,然后被复制给m

返回引用则是:可直接使用结果。

double& func(xxx) {...}
double x = func(xxx)  // 直接把func的结果赋值给x

常规返回类型是右值,不能通过地址访问。如字面值10.0,表达式x+y等。常规函数返回值之所以也是右值,是因为它的返回值位于临时内存单元中,运行到下一条语句时,它们可能不再存在。==需要注意的是:==即便函数返回的是全局变量或者static变量,传统返回机制也是copy一份临时变量,再通过这个临时变量赋值。

注意事项

在返回引用中额外需要注意:

引用用于类和对象

基类引用可以指向派生类对象。

总结

使用引用的两个主要原因:

使用传递的值而不作修改的函数:

不必严格按照以上标准。

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »