引用与指针的关系,转换

先指一处书中的错误。
《c++ primer plus》第8章的代码片段。

free_throws &clone(free_throws &ft)
{
    // free_throws *pt;
    // *pt = ft;
    // return *pt;
    // 原书代码

    // 修改后的代码
    free_throws *pt;
    pt = &ft;
    return *pt;

}

实在不清楚弄个空指针,然后往内存里赋值是在干啥。而且这段代码还不是让你运行的代码,是个例子代码,初学者我估计都得搞疯,有很大误导性。回到正题吧

1. c++引用

查阅了网上资料,c++引用的本质还是变量,有地址、有值。但是在编译阶段被处理掉了,coding的时候简化了。

2. 引用与指针的对应

如前述代码

free_throws &clone(free_throws &ft)
{
    free_throws *pt;  // 定义指针变量;
    pt = &ft;            // ft的地址赋值给指针
    return *pt;         // 返回*pt, *pt等于ft。但是函数返回值为引用,怎么回事?
}

打印地址看看

free_throws &clone(free_throws &ft)
{
    // free_throws *pt;
    // *pt = ft;
    // return *pt;
    using std::cout;

    free_throws *pt;
    pt = &ft;
    using std::cout;
    cout << "pt address: " << pt << '\n';
    return *pt;
}
three address: 0x16dc6f620
pt address: 0x16dc6f620

地址相同。赋值阶段是符合预期。这部分是正常的指针操作。

关键就在

return *pt;

这行。
返回的*pt===ft,这中间的替换从代码层面,类似与

void foo()
{
    int a = 5;      
    int *b = &a;
    int &c = *b;
    std::cout << c << '\n';
}

正常打印:5
能看出来引用是在变量所在的内存位置插个带类型的旗子(这样的描述主要是为了与指针做区分),然后直接使用变量“值”“地址”

引用是不能像指针一样做强制类型转换的。

void foo1()
{
    int a = 5;
    long &b = a;
}
//8.6.strtref.cpp:108:11: error: non-const lvalue reference to type 'long' cannot bind to a value of unrelated type 'int'
    long &b = a;
          ^   ~
1 error generated.

macos下编译不通过。从这个角度看,使用上不如指针灵活,但是更安全和方便。

3. 总结

  1. 引用不如指针灵活
  2. 由于限制条件,使用上会更加安全
  3. 在指针和引用转换、赋值的时候,一定不要被指针误导,只需要明确指针指向的值是什么即可。

4. 所有测试代码:

#include <iostream>
#include <string>

struct free_throws
{
    std::string name;
    int made;
    int attempts;
    float percent;
};

void display(const free_throws &ft);
void set_pc(free_throws &ft);
free_throws &accumulate(free_throws &target, const free_throws &source);
free_throws &clone(free_throws &ft);
void foo();

int main()
{
    free_throws one = {"Ifelsa Branch", 13, 14};
    free_throws tow = {"Andor Knott", 10, 16};
    free_throws three = {"Minnie Max", 7, 9};
    free_throws four = {"Whily looper", 5, 9};
    free_throws five = {"Long Long", 6, 14};
    free_throws team = {"Throwgoods", 0, 0};

    free_throws dup;

    set_pc(one);
    display(one);
    accumulate(team, one);
    display(team);

    display(accumulate(team, tow));
    accumulate(accumulate(team, three), four);
    display(team);

    dup = accumulate(team, five);
    std::cout << "Displaying team: \n";
    display(team);
    std::cout << "Displaying dup after assignment: \n";
    display(dup);
    set_pc(four);

    accumulate(dup, five) = four;
    std::cout << "Displaying dup after ill-advised assignment:\n";
    display(dup);

    using std::cout;
    cout << "three address: " << &three << '\n';
    free_throws &jolly = clone(three);
    cout << "Displaying jolly :\n";
    display(jolly);
    foo();
    return 0;
}

void display(const free_throws &ft)
{
    using std::cout;
    cout << "Name: " << ft.name << '\n';
    cout << " Made: " << ft.made << '\t';
    cout << "Attempts: " << ft.attempts << '\t';
    cout << "Percent: " << ft.percent << '\n';
}

void set_pc(free_throws &ft)
{
    if (ft.attempts != 0)
        ft.percent = 100.0f * float(ft.made) / float(ft.attempts);
    else
        ft.percent = 0;
}

free_throws &accumulate(free_throws &target, const free_throws &source)
{
    target.attempts += source.attempts;
    target.made += source.made;
    set_pc(target);
    return target;
}

free_throws &clone(free_throws &ft)
{
    // free_throws *pt;
    // *pt = ft;
    // return *pt;
    using std::cout;

    free_throws *pt;
    pt = &ft;
    using std::cout;
    cout << "pt address: " << pt << '\n';
    return *pt;
}

void foo()
{
    int a = 5;
    int *b = &a;
    int &c = *b;
    std::cout << c << '\n';
}

void foo1()
{
    // int a = 5;
    // long &b = a;
}
posted @ 2022-09-15 13:02  划水才是生命的真谛  阅读(204)  评论(1)    收藏  举报