C++中变量和引用有什么区别?

4

我所知晓的事实:

  1. C++ 中有三种类型的变量:变量、指针和引用。
  2. 变量是存储实际数据的内存的标签。
  3. 指针存储变量的地址。
  4. 引用是变量的别名。

我的问题:

  1. 根据观察,使用变量名和引用似乎可以互换使用。这是真的吗?
  2. 传递变量名和传递引用作为参数之间有什么区别?例如:

    void func(int a); vs void func2(int& b);

非常感谢!


不,这些名称并不完全可互换。例如,http://coliru.stacked-crooked.com/a/57a496c47639304b - chris
3个回答

15
这里有一种方法来理解它们的区别:
- 可以改变状态的对象也称为“变量”。 - 指针是对象(变量或非变量)。它们有一个状态。 - 引用是“昵称”。它们没有状态,但公开了所引用对象的状态(这就是为什么你不能重新分配引用,因为它不是一个实际的对象)。
现在,在某些情况下,引用可能被实现为指针,但从语言的角度来看,引用只不过是不是指针,它们真的是现有对象的其他名称。
由于指针是对象,有一个状态,所以将指针传递给函数将复制该状态,即指针的状态,而不是指向者的状态。然而,引用没有状态,所以如果你将引用传递给函数,你将传递所引用的对象(通过复制)。
"引用是昵称"是理解引用的最好方式。
第一个实现要求对传递的对象进行复制。也就是说,内部函数可以对a进行任何操作,而不更改传递给func()的对象,因为内部func()创建了该对象的副本并操纵该副本,而不是原始对象。
第二个实现请求"一个已经存在的对象的昵称"。首先,对象必须存在,如果传递了,就会在函数内部为其创建一个昵称。该昵称,即引用b,仍然是原始对象的昵称。这意味着对b所做的任何操作都将影响传递给func2()的原始对象。
- func()签名表示"我需要这个数据,但我不会修改原始对象"。 - func2()签名表示"我需要一个我一定会修改的对象,请传递它,以便我可以修改它"。
奖励阶段:
到此为止,如果您还不知道const,那可能会有用:在函数签名中,使用const与引用一起指定"只读"的参数。
让我澄清一下:
void func3( const int& b);

在这里,func3说:“我需要访问一个对象,但实际上我不会复制它。然而,我保证我不会改变那个对象。”
那么,为什么我们需要这个呢?因为有些对象复制起来很昂贵。int是便宜的,所以大多数人会在func()和func3()中传递它,基本上是等价的(取决于实现,但通常是真的)。
然而,如果我们想要传递一个非常大的对象,比如数据缓冲区,我们真的不想一遍又一遍地复制它,只是为了应用一些算法。因此,我们确实希望通过引用传递它。然而,根据函数的不同,有时您只需要提取信息并使用它,因此您只需要对参数进行“只读”访问。在这种情况下,您可以使用const Object&。但是,如果您需要将算法应用于传递的对象,则需要能够修改它,您可以称之为“写访问”。在这种情况下,您需要使用普通引用。要求复制基本上意味着您想操作与传递对象相同状态的对象,但不是传递的对象。
总结一下:
- func(T object):我想要一个类型为T的对象副本; - func(T& object):我想要“写访问”类型为T的对象-假设我会修改该对象!; - func(const T& object)或func(T const & object) //它们是相同的:我想读取一个对象的状态,但我保证不会修改它,我需要“只读”访问。
实际上,“只读”保证可能会使用const_cast<>违反,但那是另一回事,只在一些非常非常非常狭窄的情况下使用。
最后您需要知道的是,如果您有一个成员函数,那么您可以执行:
class K{
public:
     void func() const; // see the const?
};

在这种情况下,你所说的是函数内部基本上等同于:void func(const K* this);
在这种情况下,你可以看到this是一个指针,但它指向一个const对象。这意味着func()保证该对象是成员的(this)从未通过此函数进行修改(除了某些特定情况,参见mutable关键字,另一个长故事)。

2

假设你有以下两个函数:

void addone(int a) {
   a += 1;
}

void addone_bis(int &a) {
  a += 1;
}

如果你在main函数中调用第一个函数,那么变量的值只会在addone函数中改变,而不会在主函数中改变;但是如果你调用addone_bis函数,变量a的值也会在main函数中被改变。

int main() {
   int test_a = 10;
   int test_b = 11;

   addone(test_a);
   // test_a still equals 10.

   addone_bis(test_b);
   // test_b now equals 12.

}

我正确回答了你的问题吗?


这是不正确的。a + 1 的结果没有写回到 a。你需要使用 a += 1; 或者 ++a; - zmb
是的,你说得对。已经修复了,谢谢! - Aliou

1
你的第一个示例是所谓的“按值传递”。这意味着实际值的副本被传递到程序中。
当以第二个示例的方式传递时,这就是所谓的“按引用传递”。引用本质上是将变量传递到程序中,以便被调用程序修改其实际值而无需取消引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接