在C++中,&
符号有多个用途,但最常见的是作为引用声明符和地址运算符。以下是关于 &
在C++中的详细解释:
1. 引用声明符
当 &
用于类型名之后时,它表示引用类型。引用是变量的别名,它允许我们使用不同的名称来访问同一个变量。引用必须在声明时初始化,并且一旦初始化,就不能再指向其他对象。
int x = 10;
int& ref = x; // ref 是 x 的引用
ref = 20; // 相当于 x = 20
2. 地址运算符
当 &
用于变量之前时,它表示取地址运算符,它返回变量的内存地址。这个地址可以被赋值给一个指针变量。
int x = 10;
int* ptr = &x; // ptr 指向 x 的内存地址
3. 引用作为函数参数
通过引用传递参数可以避免复制大型对象,提高效率。而且,因为引用是对原变量的别名,所以在函数内部对引用的修改也会影响到原变量。
void modify(int& value) {
value = 20; // 修改 value 会影响调用者传递的变量
}
int main() {
int x = 10;
modify(x); // x 的值现在变为 20
return 0;
}
4. 引用返回类型
函数也可以返回引用,但通常要小心使用,因为返回的引用必须指向一个有效的、持久的对象。
int& getRef(int& value) {
return value; // 返回对传入参数的引用
}
int main() {
int x = 10;
int& ref = getRef(x); // ref 是 x 的引用
ref = 20; // x 的值现在变为 20
return 0;
}
5. 常量引用
通过在引用前加上 const
关键字,我们可以创建一个指向常量的引用,或者称为常量引用。这意味着我们不能通过常量引用来修改它所指向的值。
void print(const int& value) {
// 我们不能修改 value 的值,因为它是 const 引用
std::cout << value << std::endl;
}
int main() {
int x = 10;
print(x); // 输出 10
return 0;
}
6. 引用折叠
在C++11及以后的版本中,引入了一个名为“引用折叠”的规则,它允许在模板编程和函数返回类型中更灵活地处理引用。
7. 引用初始化列表
在类的构造函数中,可以使用引用初始化列表来初始化成员变量。
class MyClass {
public:
int value;
MyClass(int& ref) : value(ref) {} // 错误:不能直接将引用赋值给非引用成员
// 正确的做法是使用拷贝构造函数或其他方法来确保正确地初始化成员
};
8. 右值引用(C++11)
C++11引入了右值引用(&&
),它允许我们区分左值(有持久存储位置的表达式)和右值(临时对象或即将被销毁的对象)。右值引用通常与移动语义和完美转发一起使用,以提高性能和灵活性。
这只是 &
在C++中的一些基本用法。在更高级的编程中,它还可以与其他特性(如模板、lambda表达式等)结合使用。
引用作为返回值
基本格式:类型标识符 &函数名(形参列表及类型说明)
{函数体}
引用作为函数的返回值时,函数的返回值可以理解为函数返回了一个变量(事实上,函数返回引用时,它返回的是一个指向返回值的隐式指针),因此,值为引用的函数可以用作赋值运算符的左操作数。 另外,用引用返回一个函... 全局变量,局部静态变量,局部动态分配变量都可以作为函数返回值。
(1)不能返回局部变量的引用。因为局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
(2)静态变量或者全局变量,可以成为其他引用的初始值。
(3)不能返回函数内部new分配的内存的引用。
(4)可以返回类成员的引用,但最好是const。
int& test1()
{
int b = 0;
return b;
}
int& test2()
{
static int c = 1;
return c;
}
int e = 2;
int main()
{
int& a = test1(); //错误(1)
int& d = test2(); //正确(2)
int& f = e; //正确(2)
cout << a << endl;
cout << d << endl;
cout << f << endl;
cout << test2() << endl; //打印改变前的
d = 5;
cout << test2() << endl; //打印改变后的
return 0;
}
—
注:1. 不要返回一个临时变量的引用。
2. 如果返回对象出了当前函数的作用域依旧存在,则最好使用引用返回,因为这样更高效。
引用和指针的不同点:
1. 引用在定义时必须初始化,指针没有要求
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型 实体
3. 没有NULL引用,但有NULL指针
4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占 4个字节)
5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全
(1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如意的问题。
(2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。
(3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
(4)使用引用的时机。流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。