42

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

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

4

5 回答 5

75

似乎让您感到困惑的是,声明为通过引用传递(使用&)的函数没有使用实际地址调用,即&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
于 2013-08-09T13:12:04.673 回答
19

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

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

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

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

于 2013-08-09T12:59:26.450 回答
2

好的,看来您将按引用传递与按值传递混淆了。此外,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变量的指针也被传递到堆栈上。该函数使用此指针(它只是一个内存地址)来取消引用并更改该内存地址处的值,以“返回”结果。由于函数需要一个内存地址作为参数,所以我们必须为它提供一个,我们通过&对变量使用“address-of”运算符来做到这一点result

以下是通过引用传递的两个 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.

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

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

于 2017-11-20T18:12:20.640 回答
1

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

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

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

于 2013-08-09T12:53:35.513 回答
0

我必须补充的一件事是 C 中没有引用。

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

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

int CDummy::isitme (reference CDummy param)

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

于 2013-08-09T13:18:10.607 回答