《c++入门经典》笔记12

《c++入门经典》笔记12

第12章 创建引用

12.1什么是引用

引用是一个别名。创建引用时,使用另一个对象(目标)的名称来初始化它,从此以后该引用就像是目标的另一个名称,对引用执行的任何操作实际上针对的就是目标。

有些书上说引用就是指针,这不正确。虽然引用常常是使用指针实现的,但是只有编译器开发人员关心这一点,作为程序员,必须区分这两种概念。

指针是存储另一个对象的地址的变量,而引用时对象的别名。

12.2创建引用

要创建引用,需要指定目标对象的类型、引用运算符(&)和引用名。

程序清单12.1 Reference.cpp

#include <iostream>

int main()
{
    int intOne;
    int &rSomeRef = intOne;

    intOne = 5;
    std::cout << "intOne: " << intOne << std::endl;
    std::cout << "rSomeRef: " << rSomeRef << std::endl;

    rSomeRef = 7;
    std::cout << "intOne: " << intOne << std::endl;
    std::cout << "rSomeRef: " << rSomeRef << std::endl;
    return 0;
}

12.3将地址运算符用于引用

如果请求返回引用的地址,就将返回它指向的目标的地址。这是引用的特征:他们是目标的别名

程序清单12.2 Reference2.cpp

#include <iostream>

int main()
{
    int intOne;
    int &rSomeRef = intOne;

    intOne = 5;
    std::cout << "intOne: " << intOne << std::endl;
    std::cout << "rSomeRef: " << rSomeRef << std::endl;

    std::cout << "&intOne: " << &intOne << std::endl;
    std::cout << "&rSomeRef: " << &rSomeRef << std::endl;
    return 0;
}

通常,使用引用时,不将地址运算符用于它,而像使用目标变量那样使用引用。

程序清单12.3 Assignment.cpp

#include <iostream>

int main()
{
    int intOne;
    int &rSomeRef = intOne;

    intOne = 5;
    std::cout << "intOne:	" << intOne << std::endl;
    std::cout << "rSomeRef:	" << rSomeRef << std::endl;
    std::cout << "&intOne:	" << &intOne << std::endl;
    std::cout << "&rSomeRef:	" << &rSomeRef << std::endl;

    int intTwo = 8;
    rSomeRef = intTwo;
    std::cout << "
intOne:	" << intOne << std::endl;
    std::cout << "intTwo:	" << intTwo << std::endl;
    std::cout << "rSomeRef:	" << rSomeRef << std::endl;
    std::cout << "&intOne:	" << &intOne << std::endl;
    std::cout << "&intTwo:	" << &intTwo << std::endl;
    std::cout << "&rSomeRef:	" << &rSomeRef << std::endl;
    return 0;
}

12.4可引用的目标

因为对象也是一种变量,所以可引用任何对象,包括用户定义的对象。可以像使用对象那样使用对象的引用:访问成员数据和成员函数时,使用类成员访问运算符(.)与内置类型的引用一样,指向对象的引用也是对象的别名。

12.5空指针和空引用

指针未初始化或被删除时,应将其赋为nullptr,但引用不一样,引用不能为空,让引用指向空对象的程序是非法的。

12.6按引用传递函数参数

前面知道了函数的两个局限性:参数按值传递;return语句只能返回一个值。

通过将值按引用传递给函数,可消除这两种局限性。在c++中,按引用传递时通过两种方式完成的:使用指针和使用引用。他们的语法不同,但效果相同:不是在函数作用域内创建备份(也就是不是值拷贝),而是将原始对象传递给函数。

程序清单12.4 ValuePasser.cpp

#include <iostream>
void swap(int x, int y);

int main()
{
    int x = 5, y = 10;
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    swap(x, y);
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    return 0;
}

void swap(int x, int y)
{
    int temp;
    std::cout << "Swap. Before swap,x: " << x << " y: " << y << std::endl;
    temp = x;
    x = y;
    y = temp;
    std::cout << "Swap. After swap,x: " << x << " y: " << y << std::endl;
}

main()中的值都没变,可见值拷贝并不能改变原参的值

使用指针实现swap()

程序清单12.5 PointerSwap.cpp

#include <iostream>
void swap(int *x, int *y);

int main()
{
    int x = 5, y = 10;
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    swap(&x, &y);//将地址作为参数传递
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    return 0;
}

void swap(int *px, int *py)//参数声明为指针
{
    int temp;
    std::cout << "Swap. Before swap,*px: " << *px << " *py: " << *py << std::endl;
    temp = *px;
    *px = *py;
    *py = temp;
    std::cout << "Swap. After swap,*px: " << *px << " *py: " << *py << std::endl;
}

使用引用实现swap()

c++的目标之一时,避免函数的调用者操心函数的工作原理,而将注意力放在函数的功能和返回值上。传递指针将负担转嫁给了调用方,而这种负担原本不应该由调用方来承担:调用方必须知道将要交换的对象的地址传入。

明白引用语法的负担应由函数的实现方承担。为此,可使用引用。

程序清单12.6 ReferenceSwap.cpp

#include <iostream>
void swap(int &x, int &y);

int main()
{
    int x = 5, y = 10;
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    swap(x, y);
    std::cout << "Main. Before swap,x: " << x << " y: " << y << std::endl;
    return 0;
}

void swap(int &rx, int &ry)//参数声明为引用
{
    int temp;
    std::cout << "Swap. Before swap,rx: " << rx << " ry: " << ry << std::endl;
    temp = rx;
    rx = ry;
    ry = temp;
    std::cout << "Swap. After swap,rx: " << rx << " ry: " << ry << std::endl;
}

可见两种方式(指针传地址、引用传原参)达到的效果是一样的,但是引用传递中,调用方只需传递变量,且在函数内部,需要使用的特殊符号减少了,降低了程序的复杂性。引用将常规变量方便而易于使用的特点和指针的强大融为一体。

12.7理解函数头和原型

函数原型的另一个重要用途:通过查看原型中声明的参数(函数原型通常放在头文件中),程序员知道swap()的参数是按指针还是引用传递的,从而将正确调用他们。

在c++中,类的使用者(其他类中使用该类的函数)依赖于头文件来获悉需要的所有信息。头文件相当于类或函数的接口,而实际实现对使用者是隐藏的。这让程序员能够将主要精力放在要解决的问题上,而使用类或函数时无需关心它是如何实现的。

12.8返回多个值

(哦,这说和没说是一样的,还是只能return一个东西)

一种解决办法是将多个对象按引用传入函数,然后在函数中将正确的值赋给这些对象。由于按引用传递让函数能够修改原始对象,因此这相当于让函数能够返回多项信息。这种函数未使用函数的返回值,可将其(指返回值)用于报告错误。

另一种办法是使用指针或引用来实现。

程序清单12.7 ReturnPointer.cpp

#include <iostream>

short factor(int, int *, int *);

int main()
{
    int number, squared, cubed;
    short error;
    std::cout << "Enter a number(0 - 20): ";
    std::cin >> number;

    error = factor(number, &squared, &cubed);

    if (!error)
    {
        std::cout << "number: " << number << "
";
        std::cout << "square: " << squared << "
";
        std::cout << "cubed: " << cubed << "
";
    }
    else
        std::cout << "Error encountered!!
";
    return 0;
}

short factor(int n, int *pSquared, int *pCubed)
{
    short vaule = 0;
    if (n > 20)
    {
        vaule = 1;
    }
    else
    {
        *pSquared = n * n;
        *pCubed = n * n * n;
        vaule = 0;
    }
    return vaule;
}

按引用返回值

虽然程序ReturnPointer.cpp可行,但是如果使用引用而不是指针,将更容易理解和维护。

程序清单12.8 ReturnReference.cpp

#include <iostream>

enum ERR_CODE//枚举
{
    SUCCESS,
    ERROR
};

ERR_CODE factor(int, int &, int &);

int main()
{
    int number, squared, cubed;
    ERR_CODE result;

    std::cout << "Enter a number(0 - 20): ";
    std::cin >> number;

    result = factor(number, squared, cubed);

    if (result == SUCCESS)
    {
        std::cout << "number: " << number << "
";
        std::cout << "square: " << squared << "
";
        std::cout << "cubed: " << cubed << "
";
    }
    else
        std::cout << "Error encountered!!
";
    return 0;
}

ERR_CODE factor(int n, int &pSquared, int &pCubed)
{
    short vaule = 0;
    if (n > 20)
    {
        return ERROR;
    }
    else
    {
        pSquared = n * n;
        pCubed = n * n * n;
        return SUCCESS;
    }
}

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 《c++入门经典》笔记12