在C++中通过引用传递对象

passing object by reference in C++

本文关键字:对象 引用 C++      更新时间:2023-10-16

在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;
}

但令我惊讶的是,当通过引用传递对象时,对象本身的名称起到了作用(不需要&符号),并且在函数的声明/定义过程中,参数之前不需要*符号。下面的例子应该很清楚:

// 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;
}

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

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

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

void foo(int& x);

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

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

int y = 5;
foo(y);

并且CCD_ 5将通过引用传递。

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

#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

引用实际上是一个指针,里面有足够的糖,让它尝起来很美味…;)

但它也使用了与指针不同的语法,这使得使用引用比使用指针更容易。正因为如此,我们在调用接受指针的函数时不需要&——编译器会为您处理。并且您不需要*来获取引用的内容。

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

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

好吧,看来您混淆了按引用传递和按值传递。此外,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上使用&"address of"运算符来实现的。

以下是两个C++示例的pass-by-reference

// 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

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

希望我涵盖了所有的事情,而且这一切都是可以理解的。

在上述情况下通过引用传递只是实际对象的alias

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

与CCD_ 22相比,CCD_ 21具有许多优点。

我必须补充的一点是,在C.中没有引用

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

如果有一些"reference"关键字而不是&你可以写

int CDummy::isitme (reference CDummy param)

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