【问题标题】:passing object by reference in C++在 C++ 中通过引用传递对象
【发布时间】:2013-08-11 09:45:02
【问题描述】:

在C++(也是C)中通过引用传递变量的常用方法如下:

void _someFunction(dataType *name){ // dataType e.g int,char,float etc.
/****
definition
*/
}

int main(){
    dataType v;
    _somefunction(&v);  //address of variable v being passed
    return 0;
}

但令我惊讶的是,当通过引用传递对象时,我注意到对象本身的名称服务于目的(不需要& 符号)并且在函数的声明/定义期间没有@987654323 @ 符号在参数之前是必需的。 下面的例子应该清楚:

// this
#include <iostream>
using namespace std;

class CDummy {
  public:
    int isitme (CDummy& param);     //why not (CDummy* param);
};

int CDummy::isitme (CDummy& param)
{
  if (&param == this) return true;
  else return false;
}

int main () {
  CDummy a;
  CDummy* b = &a;
  if ( b->isitme(a) )               //why not isitme(&a)
    cout << "yes, &a is b";
  return 0;
}

我很难理解为什么要对 class 进行这种特殊处理。即使是几乎像一个类的结构也不会以这种方式使用。 对象名称是否像数组一样被视为地址?

【问题讨论】:

  • 您的前提是错误的:在 C++ 中通过引用传递对象的正确方法是 void someFunction(dataType&amp; name)void someFunction(const dataType&amp; name)。在 C++ 中,reference 一词具有特定含义。
  • 我建议您需要阅读一些 C++ 书籍。你是通过指针传递(首先是你的变体)和通过引用传递(第二个)。
  • “我很难理解为什么要对 class 进行这种特殊处理。即使是几乎像 class 的结构也不能这样使用。” -- 没有类的特殊待遇。结构以这种方式使用。即使是简单的内置类型(int、char、double 等)也可以这样使用。您从哪里获得有关 C++ 的信息?
  • 如果你想传递一个对象的地址,any 类型(任何类或结构,或 buitlin 类型),你首先需要一个接受地址的函数(或指针)。该函数将具有这样的签名:void somefunction(int * name)——你可以像这样将它传递给函数:int v; somefunction(&amp;v);——如果你想传递一个对象(同样,any 类型) 通过引用(在 C++ 意义上),首先你需要一个带有这样签名的函数:void somefunction(int &amp; name) -- 然后你可以像这样传递它:int v; somefunction(v);
  • 另外,您似乎区分了“变量”和“对象”。我们不在 C++ 中这样做。内置类型和类类型之间存在一些差异,主要是由于历史。但在大多数情况下,该语言努力工作,并且大部分成功地确保两者都是该语言中的一等公民,并受到同等对待。

标签: c++ class object syntax


【解决方案1】:

在上述情况下通过引用传递只是一个alias 用于实际对象。

您将使用不同的名称来引用实际对象。

pointer references 相比,references 提供了许多优势。

【讨论】:

    【解决方案2】:

    引用实际上是一个指针,它含有足够的糖分让它尝起来很好吃……;)

    但它也对指针使用了不同的语法,这使得使用引用比使用指针更容易一些。因此,在调用接受指针的函数时,我们不需要&amp; - 编译器会为您处理。而且您不需要* 来获取参考的内容。

    将引用称为别名是非常准确的描述 - 它是“同一事物的另一个名称”。因此,当a 作为引用传递时,我们实际上传递的是a,而不是a 的副本——它是通过传递a 的地址(在内部)完成的,但您不需要担心它是如何工作的[除非您正在编写自己的编译器,但是在编写自己的编译器时您需要了解许多其他有趣的事情,而您在编程时无需担心]。

    请注意,intclass 类型的引用工作方式相同。

    【讨论】:

    • “引用实际上是一个指针,含有足够的糖分让它尝起来很好吃”。我要把它打印出来,装裱起来挂在墙上:)
    【解决方案3】:

    让您感到困惑的是,声明为按引用传递(使用&amp;)的函数不是使用实际地址调用的,即&amp;a

    简单的答案是将函数声明为传递引用:

    void foo(int& x);
    

    是我们所需要的。然后自动通过引用传递。

    你现在这样调用这个函数:

    int y = 5;
    foo(y);
    

    y 将通过引用传递。

    你也可以这样做(但你为什么要这样做?口头禅是:尽可能使用引用,需要时使用指针):

    #include <iostream>
    using namespace std;
    
    class CDummy {
    public:
        int isitme (CDummy* param);
    };
    
    
    int CDummy::isitme (CDummy* param)
    {
        if (param == this) return true;
        else return false;
    }
    
    int main () {
        CDummy a;
        CDummy* b = &a;             // assigning address of a to b
        if ( b->isitme(&a) )        // Called with &a (address of a) instead of a
            cout << "yes, &a is b";
        return 0;
    }
    

    输出:

    yes, &a is b
    

    【讨论】:

    • @BenjaminLindley 实际上,我是一名尝试一切的学生。在使用了 6 个月的 python 之后,我目前除了 c++ 什么都不做 :)
    • 啊,好吧。我刚刚查看了您的个人资料,发现 Java 是最常用的语言标签。我暂时放弃我的投票。 :)
    • @Keyser 是的,直到现在我认为唯一的方法是声明一个函数(使用*)并调用它们(使用&amp;)(利用引用调用)如我的第一个所示上面的代码。但你的回答让我大开眼界。 100% 满意。
    • @KunalKrishna 很高兴我能帮上忙!
    • 我不明白你为什么这样做:CDummy* b = &amp;a;
    【解决方案4】:

    我必须补充一点,C 中没有引用。

    其次,这是语言语法约定。 & - 是一个地址运算符,但它也意味着一个引用 - 一切都取决于美国的情况

    如果有一些“参考”关键字而不是 & 你可以写

    int CDummy::isitme (reference CDummy param)
    

    但这是 C++,我们应该接受它的优点和缺点......

    【讨论】:

    • C 中有引用,但它不像 C++ 那样是官方语言术语。 “参考”是一个广泛使用的编程术语,早在 C++ 标准化它之前就已经存在。传递指向对象的指针就是通过引用传递该对象。
    【解决方案5】:

    好的,看来您将传递引用与传递值混淆了。此外,C 和 C++ 是不同的语言。 C 不支持传递引用。

    下面是两个值传递的 C++ 示例

    // ex.1
    int add(int a, int b)
    {
        return a + b;
    }
    
    // ex.2
    void add(int a, int b, int *result)
    {
        *result = a + b;
    }
    
    void main()
    {
        int result = 0;
    
        // ex.1
        result = add(2,2); // result will be 4 after call
    
        // ex.2
        add(2,3,&result); // result will be 5 after call
    }
    

    ex.1 被调用时,常量22 通过在堆栈上制作它们的本地副本传递到函数中。当函数返回时,堆栈被弹出,堆栈上传递给函数的任何东西都有效地消失了。

    ex.2中也发生了同样的事情,除了这一次,指向int 变量的指针也被传递到堆栈上。该函数使用此指针(它只是一个内存地址)来取消引用并更改该内存地址处的值,以“返回”结果。由于该函数需要一个内存地址作为参数,所以我们必须为其提供一个,我们通过在变量result 上使用&amp;“address-of”运算符来实现。

    这里有两个 C++ 引用传递示例

    // ex.3
    int add(int &a, int &b)
    {
        return a+b;
    }
    
    // ex.4
    void add(int &a, int &b, int &result)
    {
        result = a + b;
    }
    
    void main()
    {
        int result = 0;
    
        // ex.3
        result = add(2,2); // result = 2 after call
        // ex.4
        add(2,3,result); // result = 5 after call
    }
    

    这两个函数的最终结果与前两个示例相同,但不同之处在于它们的调用方式以及编译器如何处理它们。

    首先,让我们弄清楚传递引用的工作原理。在传递引用中,通常编译器实现将在最终可执行文件中使用“指针”变量来访问引用的变量,(或者似乎是共识)但这不一定是真的。从技术上讲,编译器可以简单地直接替换引用变量的内存地址,我怀疑这比通常认为的更真实。因此,当使用引用时,它实际上可以生成更高效的可执行文件,即使只是一点点。

    接下来,显然使用传递引用调用函数的方式与传递传递值没有什么不同,其效果是您可以直接访问函数中的原始变量。通过对调用者隐藏实现细节,这具有封装的结果。缺点是如果不更改函数外部的原始变量,则无法更改传入的参数。在您希望通过不必复制大对象来提高性能但又不想修改原始对象的函数中,请在引用参数前加上const

    最后,与指针变量不同,您不能在创建后更改引用,并且必须在创建时对其进行初始化。

    希望我涵盖了所有内容,并且一切都可以理解。

    【讨论】:

      猜你喜欢
      • 2011-07-06
      • 1970-01-01
      • 2018-04-03
      相关资源
      最近更新 更多