C ++:参数传递“通过引用传递”

时间:2013-11-07 02:52:13

标签: c++ function parameters reference

我理解与任何其他变量一样,参数的类型决定了参数与其参数之间的交互。我的问题是,为什么你会引用一个参数vs为什么你不参考?为什么有些函数参数引用而有些参数没有?难以理解这样做的好处,有人可以解释一下吗?

4 个答案:

答案 0 :(得分:48)

通过引用传递的能力存在有两个原因:

  1. 修改函数参数的值
  2. 为避免因性能原因而复制对象
  3. 修改参数的示例

    void get5and6(int *f, int *s)  // using pointers
    {
        *f = 5;
        *s = 6;
    }
    

    这可以用作:

    int f = 0, s = 0;
    get5and6(&f,&s);     // f & s will now be 5 & 6
    

    OR

    void get5and6(int &f, int &s)  // using references
    {
        f = 5;
        s = 6;
    }
    

    这可以用作:

    int f = 0, s = 0;
    get5and6(f,s);     // f & s will now be 5 & 6
    

    当我们通过引用传递时,我们传递变量的地址。通过引用传递类似于传递指针 - 在这两种情况下只传递地址。

    例如:

    void SaveGame(GameState& gameState)
    {
        gameState.update();
        gameState.saveToFile("save.sav");
    }
    
    GameState gs;
    SaveGame(gs)
    

    OR

    void SaveGame(GameState* gameState)
    {
        gameState->update();
        gameState->saveToFile("save.sav");
    }
    
    GameState gs;
    SaveGame(&gs);
    

    <小时/> 由于只传递了地址,因此变量的值(对于大型对象来说可能非常大)不需要复制。因此,通过引用传递可以提高性能,尤其是在以下情况下:

    1. 传递给函数的对象很大(我会在这里使用指针变量,以便调用者知道函数可能会修改变量的值)
    2. 可以多次调用该函数(例如,在循环中)
    3. 另外,请阅读const个参考文献。使用时,无法在函数中修改参数。

答案 1 :(得分:22)

This article helped me a lot.

请忘记现在的指针。拿出一粒盐。

引用对象。当您通过引用传递时,您传递 对象。

当您通过值传递时,您传递对象的副本; 另一个对象。它可能具有相同的状态,但它是不同的实例;克隆。

因此,如果您:

通过引用可能是有意义的
  • 需要在函数
  • 中修改 对象
  • 不需要(或想要)修改 对象,但是希望避免复制它只是为了将其传递给函数。这将是const参考。

如果您:

,通过价值可能是有意义的
  • 想从相同的 twin 开始,让原始双胞胎不受干扰
  • 不关心复制对象的成本(例如,我不会通过引用传递int,除非我想修改它。)

在这里,看看这段代码:

#include<iostream>

struct Foo {
  Foo() { }
  void describe() const {
    std::cout<<"Foo at address "<<this<<std::endl;
  }  
};

void byvalue(Foo foo) {
  std::cout<<"called byvalue"<<std::endl;
  foo.describe();
}

void byreference(Foo& foo) {
  std::cout<<"called byreference"<<std::endl;  
  foo.describe();
}

int main() {
  Foo foo;
  std::cout<<"Original Foo"<<std::endl;
  foo.describe();
  byreference(foo);
  byvalue(foo);
}

并按照以下方式编译:{{1​​}}

运行它:g++ example.cpp

并检查输出(计算机中的实际地址可能有所不同,但这一点仍然存在):

./a.out

请注意Original Foo Foo at address 0x7fff65f77a0f called byreference Foo at address 0x7fff65f77a0f called byvalue Foo at address 0x7fff65f779f0 地址与called byreference地址的相同方式(均为Original Foo)。并注意0x7fff65f77a0f地址不同called byvalue)的方式。

把它提升一个档次。将代码修改为如下所示:

0x7fff65f779f0

以相同的方式编译它,并注意输出(注释不在输出中;为清晰起见包括在内):

#include<iostream>
#include<unistd.h> // for sleeping

struct Foo {
  Foo() { }
  Foo(const Foo&) {
    sleep(10); // assume that building from a copy takes TEN seconds!
  }
  void describe() const {
    std::cout<<"Foo at address "<<this<<std::endl;
  }  
};

void byvalue(Foo foo) {
  std::cout<<"called byvalue"<<std::endl;
  foo.describe();
}

void byreference(Foo& foo) {
  std::cout<<"called byreference"<<std::endl;  
  foo.describe();
}

int main() {
  Foo foo;
  std::cout<<"Original Foo"<<std::endl;
  foo.describe();
  byreference(foo);
  byvalue(foo);  
}

因此,该代码旨在夸大副本的成本:当您通过引用进行调用时,不会产生此成本。当你按价值打电话时,你必须等待十秒钟。

注意:我的代码是使用GCC 4.8.1在OS X 10.7.4中编译的。如果您在Windows中,可能需要与Original Foo Foo at address 0x7fff64d64a0e called byreference Foo at address 0x7fff64d64a0e # this point is reached "immediately" called byvalue # this point is reached TEN SECONDS later Foo at address 0x7fff64d64a0f 不同的内容才能使unitsd.h来电。

也许这有帮助。

答案 2 :(得分:1)

使用传递参考的优点: 您不必创建只传递内存指针的数据副本。 (巨大的表现胜利认为如果你有一个巨大的物体,你传过来)。 您可以“返回”多个值我知道c / c ++中的某些函数返回一个数字,其中一个参数是指向被操纵的数据的指针。

使用传递引用的缺点: 您必须小心修改传递的数据,因为它可能会导致您可能想要或可能不想要的副作用。

答案 3 :(得分:1)

通过引用同样是通过指针手动传递变量,但是通过引用不会让用户处理“容易搞乱”的指针。