💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 一.概述 1. **为什么要有引用** + 指针不够安全,当指针指向了一个非法的地址,访问指针会出现未定义的行为。 2. **概念** 引用是个别名,当建立引用时,程序用另一个变量或对象(目标)的名字初始化它。 + 引用不占存储空间。 + 引用只有声明,没有定义,而且只能声明一次。 + 声明引用时必须初始化。 >[danger]赋值不是建立新的引用,而是修改被引用对象的值。 ```c++ int a = 2020; int &b = a;//声明一个左值引用 const int &c = 2020; //ok b = 2021;//对引用赋值(直接修改a值,而不是建立一个新的引用) cout<<a;//2021 ``` ## [11+]二.引用的类型(新版) 1. **左值引用** 只能引用左值 + 声明 `const 类型名 &标识符` + **左值引用不可引用右值** 若引用一个右值,则程序会尝试去创建一个临时变量,其作用域到语句末尾。由于它的作用域比引用的作用域短,编译器会报错。 + 对于类类型、对象,当形参为 `T&` ,而传入的对象类型 `T1` 必须是 `T` 或者 `T` 的派生类。需要注意的是, **这不会进行 `T1`到 `T` 的类型转换** 。 >[warning] 以下代码只能在 VC++6.0下运行,其他编译器下运行会报错。 ```c++ #include <iostream> using std::cout; using std::ostream; class Complex { private: double real_; double imaginary_; public: Complex() : real_(0), imaginary_(0) { } Complex(double real) : real_(real), imaginary_(0) { } Complex(double real, double imaginary) : real_(real), imaginary_(imaginary) { } Complex(const Complex &old) { this->real_ = old.real_; this->imaginary_ = old.imaginary_; } Complex &operator=(const Complex &old) { this->real_ = old.real_; this->imaginary_ = old.imaginary_; return *this; } Complex &set_real(double new_val) { this->real_ = new_val; return *this; } Complex &set_imaginary(double new_val) { this->imaginary_ = new_val; return *this; } friend ostream &operator<<(ostream &os, Complex c); }; ostream &operator<<(ostream &os, Complex c) { return os << '(' << c.real_ << ',' << c.imaginary_ << ')'; } void pass_a_reference(Complex& a) {} int main() { pass_a_reference(Complex(2,3));//OK return 0; } ``` >[test-vc] >没有输出 2. **常量左值引用** 即可以引用左值,也可以引用右值。 + 声明 `const 类型名 &标识符` + 无法通过引用这种方式修改被引用变量的值。 + **常量左值引用可引用右值** 若引用一个右值,则程序会尝试去创建一个临时变量,且会延长临时变量的作用域,使其与引用的作用域相同。 + 常量左值引用的初始化 **允许类型转换** 。 3. **\[11+\][$]右值引用** 只能引用右值,不可以引用左值。 + 声明 `类型名 &&标识符` + 具名的右值引用是 **左值** ,而匿名的右值引用是 **将亡值**。 + 右值引用延长了临时变量或字面量的作用域,使其与引用的作用域相同。 > 左值引用和右值引用中的“左值”和"右值"指的是被引用的对象,而不是它本身。 4. **\[11+\][$]通用引用** 即可以引用左值,也可以引用右值。 + 声明 `类型名 &&标识符` + **发生时机** 编译器进行自动类型推断,如使用 `auto` 关键字或函数模板的类型自动推导。 + **引用折叠** 编译器会自动将奇数个 `&` 转换成 `&` ,将偶数个 `&` 转换成 `&&` 。 ```C++ template <typename T> T my_abs(T &&i); double d = -3.14; my_abs(1);//T=int 参数i的类型为 int&& my_abs(d);//T=double& 参数i的类型为 int& ```