📅  最后修改于: 2023-12-03 14:39:54.333000             🧑  作者: Mango
在 C++ 中,有多种类型的引用,如左值引用、右值引用和常量引用。对这些引用进行函数重载时,需要注意它们的区别以及各自的使用情境。
左值引用是最基础的引用类型,通过 &
符号进行声明。它可以绑定到左值(表达式、变量等可以取地址且具有持久性的数据),也可以绑定到常量左值,但不能绑定到右值。
int n = 42;
int &ref_n = n; // 正确,ref_n 是 n 的左值引用
const int &ref_c_n = n; // 正确,ref_c_n 是 n 的常量左值引用
int &ref2 = 42; // 错误,42 是右值
以下是一个函数重载的例子,其中重载函数 modify
接受一个整数的左值引用,可以修改其值。另一个重载函数 print
接受一个整数的常量左值引用,只用于输出。
void modify(int &n) {
n++;
}
void print(const int &n) {
cout << n << endl;
}
int main() {
int x = 42;
modify(x); // x 的值变为 43
print(x); // 输出 43
print(42); // 对于常量左值引用,也可以接受右值,输出 42
return 0;
}
右值引用是 C++11 新增的引用类型,通过 &&
符号进行声明。它可以绑定到右值(表达式、临时对象等具有零时性的数据),但不能绑定到左值。
int n = 42;
int &&ref_r_n = n + 1; // 正确,n + 1 是右值
int &&ref2 = n; // 错误,n 是左值
右值引用最常见的用途是移动语义,即将一个对象的资源(如内存区域)移动到另一个对象,避免拷贝导致的性能损失。
以下是一个利用右值引用实现移动语义的例子。我们定义了一个简单的类 MyVector
,其中包含一个指向动态数组的指针。在复制构造函数和赋值运算符中,我们利用右值引用来实现资源的移动。
class MyVector {
public:
MyVector() { p = nullptr; }
MyVector(int n) {
p = new int[n];
for (int i = 0; i < n; i++) {
p[i] = 0;
}
}
MyVector(const MyVector &rhs) { // 复制构造函数
p = nullptr;
if (rhs.p != nullptr) {
p = rhs.p;
rhs.p = nullptr;
}
}
MyVector &operator=(MyVector &&rhs) { // 赋值运算符
if (p != rhs.p) {
delete[] p;
p = rhs.p;
rhs.p = nullptr;
}
return *this;
}
~MyVector() { delete[] p; }
private:
int *p;
};
int main() {
MyVector v1(10), v2;
v2 = std::move(v1); // 调用赋值运算符,v2 获得 v1 的资源
return 0;
}
常量引用是指对于一个常量对象或临时对象的引用,通过 const&
符号进行声明。它不能被用于修改对象的值,而只能用于读取。
int n = 42;
const int &ref_c_n = n; // 正确,ref_c_n 是 n 的常量左值引用
const int &ref2 = 42; // 也可以绑定到一个右值
int &ref3 = ref_c_n; // 错误,不能用一个非常量引用绑定到一个常量引用
以下是一个函数重载的例子,其中重载函数 print
既可以接受一个整数的左值引用,也可以接受一个整数的常量引用。对于常量引用的情况,不能修改其值。
void print(int &n) {
n++;
cout << n << endl;
}
void print(const int &n) {
cout << n << endl;
}
int main() {
int x = 42;
int &ref_n = x;
const int &ref_c_n = x;
print(ref_n); // x 的值变为 43,输出 43
print(ref_c_n); // 输出 42
print(42); // 对于常量引用,也可以接受右值,输出 42
return 0;
}
对于不同类型的引用,在函数重载时应该使用合适的引用类型进行参数声明。左值引用可以用于修改对象内容,右值引用可以用于实现资源的移动,常量引用可以方便地读取常量对象或临时对象。合理地使用不同类型的引用,可以避免不必要的复制、提高性能并增强程序的可读性。