什么时候参考变量合适?为什么?你能解释实际的语法和位置吗?

Ery*_*ryn 16 c++ variables reference

我是C++的新手.我们最近开始在课堂上探索参考变量,我对它们非常困惑.不一定如何做到这一点,因为我知道他们切换变量值,但更多的是为什么开发人员想做这样的事情呢?他们完成了什么?他们节省了记忆吗?他们是否避免必须返回信息?

这是我们正在开展的项目的一部分.我们需要包含至少一个参考变量.我可以看到如何在没有引用变量的情况下编写程序,但是我没有看到引用变量在哪里有用或必要.

"用户可能希望得到一到多个房间的估计.费率是根据墙壁和/或天花板的平方英尺计算的.公司估计需要2.5小时才能绘制200平方英尺的墙面空间和3.2小时的空间.在天花板上绘制同一区域.人工费为每小时40美元.如果绘画WALLS的工作总空间超过1400平方英尺,则客户可以获得1400平方英尺以上所有平方英尺的15%折扣.绘画天花板的折扣.

该计划应以专业格式打印出估计费用的最终报告.

程序应在退出前询问用户是否要进行更多计算."

我不是在找你们为我做作业,作为参考,我们刚刚完成了学习功能.我很好,但有很多东西通过这些网站阅读,我不明白.

而且,实际上,studentID将设置为21654.我是否正确理解这一点?

让我们再试一次:

我已经审查了这个建议的重复.虽然它确实涵盖了使用参考变量而不是指针的优点/缺点的基础知识,并讨论了使用两者的多种原因,但我仍在质疑何时(何时适当与不必要)以及为什么(为什么)的基本概念在某些情况下是否合适,它对程序有什么好处?)

我应该使用这些变量以及如何(实际的语法和位置).几乎每个人都很棒,我通过与你的互动学到了很多东西.尽管这对于经验丰富的编码员来说是多次重复和刺激,但这对我来说都是新的,我需要尽可能多地参与对话,因为我需要这些信息.我已经在许多项目中使用了Stack Overflow,例如,了解Java的newString.equalsIgnoreCase(),我很欣赏你的知识.我只能告诉你实话,如果那不够好那么它就是它的本质.

好的,让我回顾一下到目前为止的理解:

参考变量倾向于减少函数和/或程序中不希望的变量修改.

引用变量用于修改函数内的现有变量

这很有用,因为它可以"移动"值,同时最大限度地减少对这些值的复制.

引用变量修改函数/程序中的现有变量

我不知道你们是否仍然可以阅读或不阅读,因为它已被标记为重复.我一直在玩你们给我的一些迷你程序,重读我书的部分内容,做进一步的研究等等,我我在初级阶段理解.这些引用变量允许您更改和/或使用代码中的其他变量,而无需将它们直接引入代码中.我不记得哪个用户正在使用foo(hubble,bubble)示例,但是他/她的代码终于让它点击了.您实际上正在使用和/或重新分配变量,而不仅仅使用该值.

msc*_*msc 20

引用变量只是变量的别名.当您想要传递值而不是将相同的变量复制到不同位置的内存中时,您可以使用它.因此,使用引用,可以避免复制,从而节省内存.

根据Bjarne Stroustrup的常见问题解答:

C++继承了C的指针,因此我无法在不引起严重兼容性问题的情况下删除它们.引用对于几个方面很有用,但我在C++中引入它们的直接原因是支持运算符重载.例如:

void f1(const complex* x, const complex* y)    // without references
    {
        complex z = *x+*y;    // ugly
        // ...
    }

    void f2(const complex& x, const complex& y)    // with references
    {
        complex z = x+y;    // better
        // ...
    }
Run Code Online (Sandbox Code Playgroud)

更一般地说,如果要同时具有指针功能和引用功能,则需要两种不同类型(如C++中)或单一类型上的两组不同操作.例如,对于单个类型,您既需要分配给所引用对象的操作,也需要分配给引用/指针的操作.这可以使用单独的运算符完成(如Simula).例如:

Ref<My_type> r :- new My_type;
r := 7;            // assign to object
r :- new My_type;    // assign to reference
Run Code Online (Sandbox Code Playgroud)

或者,您可以依赖类型检查(重载).例如:

Ref<My_type> r = new My_type;
r = 7;            // assign to object
r = new My_type;    // assign to reference
Run Code Online (Sandbox Code Playgroud)

另外,请阅读有关指针变量和引用变量之间差异的Stack Overflow问题.


Uru*_*ann 10

我会给出三个理由,但还有更多原因.

  1. 避免不必要的副本.

    假设您编写了这样的函数:

    double price(std::vector<Room> rooms)
    {
           ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    现在,每次调用它时,Room都会复制矢量.如果您只计算几个房间的价格,但如果您想计算重新绘制帝国大厦整个办公室的成本,您将开始复制大型物品,这需要时间.

    在这种情况下,最好使用提供对数据的只读访问的常量引用:

    double price(const std::vector<Room>& rooms) { ... }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用多态

    假设您现在拥有不同类型的房间,可能是a CubicRoom和a CylindricalRoom,它们都继承自同一个基类,Room.

    不可能写:

    double price(Room room) { ... }
    
    Run Code Online (Sandbox Code Playgroud)

    然后打电话

    price(CylindricalRoom());
    //or
    price(CubicRoom());
    
    Run Code Online (Sandbox Code Playgroud)

    但是你可以定义price如下:

    double price(Room& room);
    
    Run Code Online (Sandbox Code Playgroud)

    然后一切都像你通过值一样工作.

  3. 避免回报

    假设您每次计算价格时,都希望在报告中添加格式化的报价.在C++中,您只能从函数返回单个对象,因此您无法编写:

    return price, fmtQuote
    
    Run Code Online (Sandbox Code Playgroud)

    但是,你可以这样做:

    double price(Room room, std::vector<std::string>& quotes)
    {
        ...
        quotes.push_back(fmtQuote);
        return price
    }
    
    Run Code Online (Sandbox Code Playgroud)

    显然,您可以返回一对对象std::pair<double, std::string>,但这意味着调用者必须解压缩结果.如果您打算经常调用上述功能,这将很快变得丑陋.在这种情况下,这与第一点相关:所有引号的日志都会增长,并且您希望为每次调用复制它.

    这是共享资源的典型访问模式:您希望一些函数/对象获取资源的句柄,而不是该资源的副本.

  • 你不能将rvalue传递给一个以非const引用作为参数的函数,需要添加const:`double price(const Room&room);`.否则很好,明确答案+1 :) (3认同)

Gra*_*ham 7

你在这里混合了两件完全不同的东西.三个例子展示了这两件事如何分别工作,然后一起工作......

  1. 函数可以采用值传递的参数,并返回一个值.

    double foo (double y)
    {
        y = y + 200.0;
        return y;
    }
    
    void main(void)
    {
        double hubble = 50.0;
        double bubble = 100.0;
    
        hubble = foo(bubble);
    
        std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,因为这是通过值传递的,即使foo()更改y,bubble也不会更改.hubble设置为foo()返回的值.

    然后你得到

    hubble=300, bubble=100
    
    Run Code Online (Sandbox Code Playgroud)
  2. 函数可以通过引用传递参数,并修改该参数.

    void foo (double& y)
    {
        y = y + 200.0;
    }
    
    void main(void)
    {
        double hubble = 50.0;
        double bubble = 100.0;
    
        foo(bubble);
    
        std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后你得到

    hubble=50, bubble=300
    
    Run Code Online (Sandbox Code Playgroud)

    当然hubble没有改变.但是因为bubble是通过引用传递的,所以对foo()内部的y的bubble更改会发生变化,因为该更改发生在传递的实际变量上,而不是复制的值上.

    请注意,此处没有 "return"语句.该函数不返回任何内容 - 它只是修改传递给它的变量.

  3. 当然,你可以一起使用.

    double foo (double& y)
    {
        y = y + 200.0;
        return y + 400.0;
    }
    
    void main(void)
    {
        double hubble = 50.0;
        double bubble = 100.0;
    
        hubble = foo(bubble);
    
        std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后你得到

    hubble=700, bubble=300
    
    Run Code Online (Sandbox Code Playgroud)

    和以前一样,更改y内部foo()会发生变化bubble.但现在该函数也返回一个值,该值设置hubble.

为什么你会选择返回一个值,或者修改传入的值,或者两者兼而有之?这完全取决于您编写代码的方式.

我同意你的意见,你不必在这里使用传递引用.我自己,我可能只是返回一个值.但这是一次学习练习,你被告知要这样做,所以你必须这样做.假设您的传递参考是折扣?所以函数"void discount(double&value)"接受传递的值并将其乘以0.85.这有点人为,但它会证明原理.


小智 5

引用变量是指针的更安全的替代方法.通常,在处理指针时,你并不真正关心指针(ptr),而是指向(*ptr); 然而,程序员一直搞砸和操纵ptr而不是*ptr等等.考虑以下代码:

void zeroize_by_pointer(int* p)
{
    p = 0; // this compiles, but doesn't do what you want
}
Run Code Online (Sandbox Code Playgroud)

与参考版本相比,

void zeroize_by_reference(int& p)
{
    p = 0; // works fine
}
Run Code Online (Sandbox Code Playgroud)

引用是一个好主意还有很多其他原因,但是对于那些从C++开始的人我建议关注这一点:它会让你在脚下拍摄更加困难.每当你处理指针时,你将会在某种程度上处理机器的内存模型,这在可能的情况下是一件好事.

  • 使用引用而不是指针有一个更重要的一点:你不能传递一个`null`作为引用(你可以,但那只是愚蠢的).当您使用引用时,这完全消除了对空检查的需要. (2认同)