“ &”在 C + + 声明中做什么?

我是一个 C 家伙,我正在尝试理解一些 C + + 代码:

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

函数签名与等效的 C 有什么不同:

int foo(const char *myname)

使用 string *myname和使用 string &myname有区别吗?C + + 中的 &和 C 中的 *指示指针的区别是什么?

同样地:

const string &GetMethodName() { ... }

&在这里做什么?是否有网站解释了 &在 C 和 C + + 中的不同用法?

225435 次浏览

在这里,&不用作运算符。作为函数或变量声明的一部分,&表示引用。C + + FAQ Lite 有一个非常漂亮的 参考文献一章

String * 和 string & 在几个方面有所不同。首先,指针指向数据的地址位置。引用指向数据。如果你有以下功能:

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”将被复制到该函数的返回值中,可以在调用者的内存空间中访问。

查看 c + + 中的 & (引用)操作符的一种方法是,它仅仅是一个指向指针的语法糖。例如,以下内容是 差不多等效的:

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


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

更有用的方法是在处理类时,使方法从 x-> bar ()转换为 x.bar ()。

我之所以提到 差不多,是因为使用引用会对您可以对引用执行的操作施加额外的编译时限制,以便在处理指针时避免一些问题。例如,您不能意外地更改指针,或者以任何方式使用指针,而不是引用传递给您的单数对象。

“ &”表示引用,而不是指向对象的指针(在您的例子中是常量引用)。

具有如下函数的优点

foo(string const& myname)

结束了

foo(string const* myname)

在前一种情况下,可以保证 myname 是非空的,因为 C + + 不允许 NULL 引用。因为是通过引用传递的,所以不会复制对象,就像传递指针一样。

第二个例子:

const string &GetMethodName() { ... }

将允许您返回一个常量引用,例如,一个成员变量。如果您不希望返回一个副本,并且再次保证返回的值是非空的,那么这将非常有用。例如,以下内容允许您直接进行只读访问:

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

基本上,您的责任是确保您返回的引用实际上是有效的。

在这种情况下,&使函数通过引用获取 stringname。 引用和指针之间的区别是:

  • 当您接受对变量的引用时,该引用 就是您所引用的变量。您不需要取消引用它或其他任何东西,使用引用在语义上等同于使用被引用的变量本身。
  • NULL不是引用的有效值,将导致编译器错误。因此,一般来说,如果你想在 C + + 函数中使用一个输出参数(或者一个指针/引用) ,并且允许向该参数传递一个空值,那么使用一个指针(最好是智能指针)。如果传递空值对该函数没有意义,则使用引用。
  • 你不能重新安排推荐人的座位。虽然可以将指针的值更改为指向其他内容,但是引用没有类似的功能。一旦通过引用获取一个变量,就可以有效地直接处理该变量。就像你不能通过写 b = 4;来改变 a的值一样。引用的值就是它所引用的任何东西的值。
#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);
}

这段代码在很多方面都是无效的:

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

这里发生的事情是,您正在向函数传递一个变量“ as is”。这大致相当于:

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

函数将一个常量 参考文献声明为一个字符串:

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

引用有一些特殊的属性,这使得它在许多方面比指针更安全:

  • 它永远不可能是 NULL
  • 它必须始终被初始化
  • 一旦设置,就不能更改为引用不同的变量
  • 它可以以与它所引用的变量完全相同的方式使用(这意味着您不需要像对待指针一样对它进行引用)

函数签名与等效的 C 有什么不同:

int foo(const char *myname)

有几个不同之处,因为第一个引用直接指向一个对象,而 const char*必须解引用以指向数据。

使用 string * myname 与 string & 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() { ... }

他们在这里做什么?是否有网站解释 C 和 C + + 的不同用法?

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

有一些微妙的参考-有一个在 关于参考文献的常见问题看一些更多的细节。