news 2026/6/2 3:37:06

【C++】零基础入门 · 第 12 节:引用与 const 限定符

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【C++】零基础入门 · 第 12 节:引用与 const 限定符

前面我们学了指针——C++ 中最强大也最容易出错的特性。这一节我们来学两个让代码更安全、更易读的工具:引用const 限定符

1. 引用(Reference)

1.1 什么是引用?

引用是变量的「别名」——给一个已存在的变量取另一个名字。对引用的操作,就是对原变量的操作。

inta=10;int&b=a;// b 是 a 的引用(别名)b=20;// 修改 b,就是修改 acout<<a;// 输出 20

关键点

  • 引用必须在声明时初始化
  • 引用一旦绑定到某个变量,就不能再绑定到其他变量
  • 引用不是新变量,它不占用额外的存储空间(概念上)

1.2 引用 vs 指针

引用和指针都能间接访问变量,但有本质区别:

inta=10;int*p=&a;// 指针:需要取地址,需要解引用int&r=a;// 引用:直接用,语法更简洁*p=20;// 指针需要 * 来解引用r=30;// 引用直接用,就像原变量一样
特性引用指针
初始化必须在声明时初始化可以不初始化(但不推荐)
可否为空不能为 null可以为 null
可否改变指向不能可以
语法和原变量一样需要*&
安全性更安全容易出错

简单规则:能用引用就不用指针。

1.3 引用作为函数参数

引用最常见的用途是作为函数参数,实现「传引用」:

// 传值:函数内修改不影响外部voidswapBad(inta,intb){inttemp=a;a=b;b=temp;// 外部的 a 和 b 不会变!}// 传引用:函数内修改影响外部voidswapGood(int&a,int&b){inttemp=a;a=b;b=temp;// 外部的 a 和 b 交换了!}intmain(){intx=10,y=20;swapGood(x,y);cout<<x<<" "<<y;// 输出:20 10}

1.4 引用作为函数返回值

函数可以返回引用,但要注意:不要返回局部变量的引用

// ❌ 错误:返回局部变量的引用int&badFunction(){intlocal=42;returnlocal;// local 在函数结束后被销毁,引用变成悬空引用}// ✅ 正确:返回全局变量或静态变量的引用intglobalVar=100;int&getGlobal(){returnglobalVar;// 全局变量不会被销毁}// ✅ 正确:返回参数的引用int&getElement(vector<int>&arr,intindex){returnarr[index];// 数组元素在调用者的作用域中}

返回引用的函数调用可以出现在赋值号左边:

vector<int>arr={1,2,3,4,5};getElement(arr,2)=99;// arr[2] 变成 99cout<<arr[2];// 输出 99

1.5 const 引用

const修饰引用,表示「只读」:

voidprintValue(constint&x){// x = 100; // ❌ 编译错误:不能修改 const 引用cout<<x;// ✅ 只能读取}intmain(){inta=42;printValue(a);// 正常传入printValue(100);// 也可以传入字面量!// 普通引用不能绑定到字面量,const 引用可以}

const 引用的好处

  • 防止函数意外修改参数
  • 避免拷贝,提高效率
  • 可以绑定到字面量和临时对象

2. const 限定符

2.1 const 变量

const表示「常量」,一旦初始化就不能修改:

constintMAX_SIZE=100;// MAX_SIZE = 200; // ❌ 编译错误conststring NAME="Alice";// NAME = "Bob"; // ❌ 编译错误

const 变量必须在声明时初始化,因为之后无法赋值。

2.2 const 与指针

const 和指针的组合是初学者最容易混淆的地方。记住一个口诀:const 在*左边,指向的内容不能改;const 在*右边,指针本身不能改

inta=10,b=20;// 1. 指向 const 的指针(内容只读)constint*p1=&a;// *p1 = 30; // ❌ 不能通过 p1 修改 ap1=&b;// ✅ p1 可以指向其他变量a=30;// ✅ 直接修改 a 是可以的// 2. const 指针(指针本身只读)int*constp2=&a;*p2=30;// ✅ 可以通过 p2 修改 a// p2 = &b; // ❌ p2 不能指向其他变量// 3. 指向 const 的 const 指针(都不能改)constint*constp3=&a;// *p3 = 30; // ❌// p3 = &b; // ❌

记忆方法

  • const int*:const 修饰 int,所以 int 不能改 → 内容只读
  • int* const:const 修饰int*,所以指针不能改 → 指针只读

2.3 const 成员函数

在类中,const 放在函数声明末尾,表示这个函数不会修改对象的状态:

classCircle{private:doubleradius;public:Circle(doubler):radius(r){}// const 成员函数:不会修改对象doublegetArea()const{// radius = 10; // ❌ 不能在 const 函数中修改成员变量return3.14159*radius*radius;}// 非 const 成员函数:可以修改对象voidsetRadius(doubler){radius=r;}};voidprintArea(constCircle&c){// c 只能调用 const 成员函数cout<<c.getArea()<<endl;// c.setRadius(5); // ❌ 不能调用非 const 函数}

规则:如果一个函数不修改对象状态,就把它声明为const。这样它就能被const引用和const指针调用。

2.4 常量表达式(constexpr)

C++11 引入了constexpr,比const更严格:

constintx=10;// x 是常量constexprinty=20;// y 是编译期常量constintz=getSomeValue();// ✅ 运行时确定的常量也可以// constexpr int w = getSomeValue(); // ❌ 必须编译期能确定constexprintsquare(intn){returnn*n;}constexprintresult=square(5);// 编译期计算,result = 25

constexpr告诉编译器:这个值在编译期就能确定,可以做更多优化。

2.5 mutable 关键字

有时候你需要在 const 成员函数中修改某些特定的成员变量(比如缓存、计数器)。mutable就是为此设计的:

classDataFetcher{private:mutableintaccessCount=0;// 即使在 const 函数中也能修改string data;public:stringgetData()const{accessCount++;// ✅ mutable 变量可以在 const 函数中修改returndata;}intgetAccessCount()const{returnaccessCount;}};

3. 引用与 const 的实际应用

3.1 函数参数的最佳实践

// ✅ 最佳实践:按需选择参数传递方式// 基本类型(int、double 等):传值voidprocessInt(intx){/* ... */}// 不需要修改的大对象:const 引用voidprintVector(constvector<int>&vec){for(intx:vec)cout<<x<<" ";}// 需要修改的参数:引用voidsortVector(vector<int>&vec){sort(vec.begin(),vec.end());}// 可能为空的参数:指针voidprocessMaybeNull(int*ptr){if(ptr!=nullptr){// 处理数据}}

3.2 返回值的最佳实践

classMatrix{private:vector<vector<int>>data;public:// 返回 const 引用:只读访问constvector<int>&getRow(inti)const{returndata[i];}// 返回非 const 引用:可修改访问vector<int>&getRow(inti){returndata[i];}// 返回值:小对象或需要返回新对象时intgetElement(inti,intj)const{returndata[i][j];}};

3.3 范围 for 循环中的引用

vector<int>arr={1,2,3,4,5};// 只读遍历:const 引用for(constint&x:arr){cout<<x<<" ";// 高效,不拷贝}// 修改遍历:非 const 引用for(int&x:arr){x*=2;// 原地修改每个元素}// 不用引用:会拷贝每个元素(对于大对象效率低)for(intx:arr){cout<<x<<" ";// 基本类型没问题,string 等大对象会有额外拷贝}

4. 常见陷阱

4.1 悬空引用

int&getDangling(){intlocal=42;returnlocal;// ⚠️ 返回局部变量的引用}intmain(){int&ref=getDangling();cout<<ref;// 未定义行为!可能输出垃圾值}

4.2 const 丢失

constinta=10;constint*p=&a;// int* bad = p; // ❌ 编译错误:不能丢弃 constint*bad=const_cast<int*>(p);// ⚠️ 强制转换,但修改 a 是未定义行为

4.3 引用的引用

inta=10;int&r1=a;int&r2=r1;// r2 是 a 的引用,不是 r1 的引用r2=20;cout<<a;// 输出 20

5. 小结

本节我们学习了引用和 const 限定符:

  • 引用是变量的别名,必须初始化,不能重新绑定
  • const 引用可以绑定到字面量,防止意外修改
  • const 指针有两种:指向内容的 const 和指针本身的 const
  • const 成员函数表示不修改对象状态
  • constexpr是编译期常量,比 const 更严格

最佳实践

  • 函数参数优先用const 引用(只读)或引用(需修改)
  • 不修改对象的成员函数都声明为const
  • 能用引用就不用指针
  • constexpr代替const定义编译期常量

下一节我们将学习类与对象基础——C++ 面向对象编程的起点。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/2 3:36:27

别再只会用timeout了!Windows批处理(.bat)文件隐藏的5个实用小技巧

解锁Windows批处理文件的隐藏潜力&#xff1a;5个超越timeout的高级技巧在Windows自动化任务处理中&#xff0c;批处理文件&#xff08;.bat&#xff09;常被视为简单工具&#xff0c;仅用于执行基础命令序列。然而&#xff0c;这种认知大大低估了其实际能力。许多系统管理员和…

作者头像 李华
网站建设 2026/6/2 3:34:30

2026年亲测AI论文写作软件榜单(安全合规版)

为解决学术写作中效率与合规两大核心痛点&#xff0c;以下精选8款高适配性AI论文写作工具&#xff08;按综合优先级排序&#xff09;&#xff0c;围绕中文学术规范适配、真实参考文献生成、格式标准化、高性价比四大核心维度筛选&#xff0c;同时配套分场景精准选型方案与学术合…

作者头像 李华
网站建设 2026/6/2 3:34:25

专业的AI论文平台排名(2026 真实数据)

基于功能完整性、学术适配性、用户使用体验及技术稳定性&#xff0c;以下是当前主流AI论文写作工具的综合测评排名&#xff0c;按实际应用推荐指数由高至低排列&#xff0c;并详细标注各平台的核心优势与适用领域。&#x1f3c6; 第一梯队&#xff1a;全流程学术解决方案&#…

作者头像 李华
网站建设 2026/6/2 3:32:32

LeetCode--Merge k Sorted Lists--分治策略

Merge k Sorted Lists--分治策略## [更多技术博客 http://vilins.top/](http://vilins.top/)题目Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.ExampleInput: [1->4->5,1->3->4,2->6 ] Output: 1->1…

作者头像 李华