什么'&'在C ++声明中做什么?

时间:2009-12-21 23:22:20

标签: c++ syntax operators

我是C人,我正在尝试理解一些C ++代码。我有以下函数声明:

int foo(const string &myname) {
  cout << "called foo for: " << myname << endl;
  return 0;
}

函数签名与等效C:

的区别
int foo(const char *myname)

使用string *mynamestring &myname之间有区别吗? C ++中的&和C中的*之间有什么区别来表示指针?

类似地:

const string &GetMethodName() { ... }

&在这做什么?是否有一些网站解释了在C vs C ++中&的使用方式有何不同?

7 个答案:

答案 0 :(得分:31)

“&amp;”表示引用而不是指向对象的指针(在您的情况下是一个常量引用)。

具有诸如

之类的功能的优点
foo(string const& myname) 

结束

foo(string const* myname)

在前一种情况下,保证myname为非null,因为C ++不允许NULL引用。由于您是通过引用传递的,因此不会复制该对象,就像传递指针一样。

你的第二个例子:

const string &GetMethodName() { ... }

允许您返回常量引用,例如,成员变量。如果您不希望返回副本,并且再次保证返回的值为非null,则此选项非常有用。例如,以下内容允许您进行直接的只读访问:

class A
{
  public:
  int bar() const {return someValue;}
  //Big, expensive to copy class
}

class B
{
public:
 A const& getA() { return mA;}
private:
 A mA;
}
void someFunction()
{
 B b = B();
 //Access A, ability to call const functions on A
 //No need to check for null, since reference is guaranteed to be valid.
 int value = b.getA().bar(); 
}

当然,您必须小心不要返回无效的引用。 编译器将很乐意编译以下内容(取决于您的警告级别以及如何处理警告)

int const& foo() 
{
 int a;

 //This is very bad, returning reference to something on the stack. This will
 //crash at runtime.
 return a; 
}

基本上,您有责任确保您返回的任何内容实际上都是有效的。

答案 1 :(得分:17)

此处,&不用作运算符。作为函数或变量声明的一部分,&表示引用。 C ++ FAQ Lite非常漂亮{​​{3}}。

答案 2 :(得分:7)

string *和string&amp;在几个方面有所不同。首先,指针指向数据的地址位置。参考指向数据。如果您有以下功能:

int foo(string *param1);

您必须检查函数声明以确保param1指向有效位置。比较:

int foo(string &param1);

这里,调用者有责任确保指向的数据有效。您不能传递“NULL”值,例如,上面的第二个函数。

关于第二个问题,关于方法返回值是一个引用,请考虑以下三个函数:

string &foo();
string *foo();
string foo();

在第一种情况下,您将返回对数据的引用。如果您的函数声明如下所示:

string &foo()
{
    string localString = "Hello!";
    return localString;
}

您可能会遇到一些编译器错误,因为您正在返回对该函数的堆栈中初始化的字符串的引用。在函数返回时,该数据位置不再有效。通常,您希望返回对类成员或类似内容的引用。

上面的第二个函数在实际内存中返回一个指针,因此它将保持不变。但是,您必须检查NULL指针。

最后,在第三种情况下,返回的数据将被复制到调用者的返回值中。所以,如果你的功能是这样的:

string foo()
{
    string localString = "Hello!";
    return localString;
}

你没问题,因为字符串“Hello”将被复制到该函数的返回值中,可以在调用者的内存空间中访问。

答案 3 :(得分:1)

查看&amp; (参考)c ++中的运算符只是指针的语法糖。例如,以下大致等效:

void foo(int &x)
{
    x = x + 1;
}

void foo(int *x)
{
    *x = *x + 1;
}

当你处理一个类时,更有用的是你的方法从x-&gt; bar()转到x.bar()。

我之所以说粗略的原因是使用引用会对你可以对引用做什么施加额外的编译时限制,以保护你免受处理指针时引起的一些问题。例如,您不能意外地更改指针,或以任何方式使用指针,而不是引用您已经传递的单个对象。

答案 4 :(得分:1)

#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
            int number;
            int result;
            number=5;
            cout << "The value of the variable number before calling the function : " << number << endl;
            result=add(&number);
            cout << "The value of the variable number after the function is returned : " << number << endl;
            cout << "The value of result : " << result << endl;
            return(0);
}

int add(int &p)
{
            *p=*p+100;
            return(*p);
}

这是几个计数的无效代码。通过g ++运行它会产生:

crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’

该代码的有效版本为:

#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
            int number;
            int result;
            number=5;
            cout << "The value of the variable number before calling the function : " << number << endl;
            result=add(number);
            cout << "The value of the variable number after the function is returned : " << number << endl;
            cout << "The value of result : " << result << endl;
            return(0);
}

int add(int &p)
{
            p=p+100;
            return p;
}

这里发生的是你正在将一个变量“按原样”传递给你的函数。这大致相当于:

int add(int *p)
{
      *p=*p+100;
      return *p;
}

但是,将引用传递给函数可确保您不能使用引用执行指针算术等操作。例如:

int add(int &p)
{
            *p=*p+100;
            return p;
}

无效。

如果必须使用指向引用的指针,则必须明确地执行:

int add(int &p)
{
                    int* i = &p;
            i=i+100L;
            return *i;
}

在测试运行中给出(如预期)垃圾输出:

The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792

答案 5 :(得分:1)

您的函数向字符串声明一个引用

int foo(const string &myname) {
  cout << "called foo for: " << myname << endl;
  return 0;
}

引用具有一些特殊属性,这使得它在许多方面更容易替代指针:

  • 永远不会为NULL
  • 必须始终初始化
  • 一旦设置
  • ,就无法更改为引用其他变量
  • 它可以与它所引用的变量完全相同的方式使用(这意味着你不需要像指针一样使用它)
  

函数签名与等效C:

的区别
int foo(const char *myname)

存在一些差异,因为第一个直接引用一个对象,而const char*必须取消引用才能指向数据。

  

使用string * myname vs string&amp; myname?

之间有区别吗?

处理参数时的主要区别在于您无需取消引用&myname。一个更简单的例子是:

int add_ptr(int *x, int* y)
{
    return *x + *y;
}
int add_ref(int &x, int &y)
{
    return x + y;
}

完全相同的事情。在这种情况下,唯一的区别是您不需要取消引用xy,因为它们直接引用传入的变量。

const string &GetMethodName() { ... }
  

什么是&amp;在这儿干?是否有一些网站解释了&amp;在C vs C ++中使用的方式不同?

返回对字符串的常量引用。因此调用者可以直接访问返回的变量,但只能以只读方式访问。这有时用于返回字符串数据成员而不分配额外的内存。

参考文献中有一些细微之处 - 请查看C++ FAQ on References了解更多细节。

答案 6 :(得分:0)

在此上下文中&导致函数通过引用获取stringname。 引用和指针之间的区别是:

  • 当您引用变量时,该引用 您引用的变量。你不需要取消引用它或任何东西,使用引用在语义上等于使用引用的变量本身。
  • NULL不是引用的有效值,会导致编译器错误。所以通常,如果你想在C ++函数中使用输出参数(或一般的指针/引用),并且应该允许将null值传递给该参数,那么最好使用指针(或智能指针)。如果传递null值对该函数没有意义,请使用引用。
  • 你不能'重新安排'参考。虽然指针的值可以更改为指向其他位置,但引用没有类似的功能。一旦通过引用获取变量,就可以直接有效地处理该变量。就像您无法通过编写a来更改b = 4;的值。引用的值是引用它的值。