C++的第十一天笔记

应尽可能的使用const

  • 使用const可以避免无意中修改数据的编程错误;

  • 使用const使函数能够处理const和非const实参,否则只能接收非const数据(前提:函数参数为引用 / 指针);

  • 使用const引用使函数能够正确生成并使用生成的临时变量。

将引用用于结构

结构 / 类的对象往往体积较大,值传递会触发浅拷贝深拷贝

  • 浅拷贝:仅复制成员变量的表面值(如指针)。可能导致内存被多次释放( C++ 默认)。

  • 深拷贝:会递归复制原始对象及其所有嵌套对象,生成一个完全独立的新对象。对内存的开销大(需要手动编写拷贝构造函数实现)。

指针操作繁琐可读性差,容易产生野指针,比较危险。

引用共用空间,无拷贝;语法简洁,可读性高;无空野指针,安全。

引用函数(和指针函数类似)
复制代码
 //语法:数据类型& 函数名(形参列表); 

引用可以作为函数返回值,可以避免拷贝,直接操作对象。

复制代码
 // 结构体定义(投篮数据)
 struct free_throws {
     string name;
     int made;
     int attempts;
 };
 ​
 //引用函数,用于更新数据
 free_throws& accumulate(free_throws& target, const free_throws& source) {
     // 累加投中次数和尝试次数
     target.attempts += source.attempts;
     target.made += source.made;
     
     return target;
 }
 ​
 ...
  // 初始化三个球员的数据
     free_throws player1 = {"库里", 45, 50,};
     free_throws player2 = {"汤普森", 38, 40};
     free_throws team_total = {"勇士队合计", 0,0};
  // 链式调用:将 player1 和 player2 的数据累加到 team_total
     accumulate(accumulate(team_total, player1), player2); 
  //也可以这样用
     accumulate(team_total, player1).attempts = 3;

accumulate(accumulate(team_total, player1), player2);

**引用函数可以实现链式操作。**使用无返回值函数可以操作同一片空间,但无法实现链式操作。使用值返回函数,编译器会创建临时变量,操作的不是同一片空间,不仅无效,而且创建副本对内存开销很大。

accumulate(team_total, player1).attempts = 3;

引用函数的返回值可以做左值,因为其和原数据共享空间,空间固定。倘若是值传递,由于是临时数据,编译器会报错。

将引用用于类对象

将类对象传递给函数时,C++通常的做法是使用引用。

C++里面定义了一种char*到string的转换功能,所以可以使用C风格的字符串来初始化string对象。

在传参时,引用参数是 const 类型,实参类型不正确,且可以隐式转换为形参类型,会创建临时对象,使用的是临时空间。
注:千万不要返回局部的引用,返回时引用已被销毁,执意使用编译器会警告不会报错,但程序试图执行这个引用函数的时候,程序会崩溃。

对象、继承和引用

对象是类的实例,可以通过成员函数操作。

继承是能够将特性从一个类传递到另一个类的语言特性。 派生类(子)会继承基类(父)的方法,比如基类有 name,派生类不用再定义,直接能用;

基类的引用可以指向派生类的对象。而且无需强制类型转换。

复制代码
     ...
     ofstream fout;    // 1. 创建派生类对象:ofstream是ostream的派生类,用于向文件写数据
     const char * fn = "ep-data.txt";  // 要写入的文件名(C风格字符串)
     fout.open(fn);    // 2. 打开文件:关联fout对象和"ep-data.txt"文件
     
      double objective;  // 存储望远镜物镜的焦距(单位:mm)
     // 提示用户输入物镜焦距
     cout << "请输入你的望远镜物镜焦距(单位:mm):";
     cin >> objective;  // 读取用户输入的物镜焦距
     
      // ostream& os(基类引用)直接绑定fout,无需强转 → 数据写入文件
     file_it(fout, objective);
     
     cout << "数据已写入文件!" << endl;
     fout.close();//关闭文件
     ...
复制代码
 // os:基类引用,绑定派生类对象(fout或cout),实现通用输出
 void file_it(ostream & os, double fo)
 {
     ios_base::fmtflags initial;  // 存储输出流的“初始格式状态”(用于后续恢复)
     initial = os.setf(ios_base::fixed);  // 设置输出为“固定小数格式”,并保存初始格式
 ​
     os.precision(0);  // 设置小数位数为0(整数输出)
     os << "物镜焦距:" << fo << " mm\n";  // 输出物镜焦距(os绑定fout则写文件,绑定cout则写屏幕)
 ​
     os.setf(ios::showpoint);  // 强制显示小数点(即使是整数也显示 .0)
     os.precision(1);          // 设置小数位数为1(目镜焦距保留1位小数)
 ​
     os.width(12);  // 设置下一个输出内容的宽度为12字符(右对齐,默认填充空格)
     os << "目镜焦距(mm)";  // 输出表头1
 ​
     os.setf(initial);  // 恢复输出流的初始格式(避免影响后续其他输出)
 }

ofstreamcout拥有 这些格式控制功能,os 作为基类引用,能直接调用这些继承来的功能。简单来讲就是:辈分高的类(父类)的引用/指针,可以接收(例如形参接收实参)辈分低的类(子类)的对象,接收后,这个子类对象可以使用父类的方法,但不能使用子类特有的方法。子类的引用/指针也不能接收父类的对象。

何时使用引用参数
  • 大对象,值传递会创建一个完整的副本,如果参数是体积大的对象,对内存的开销很大。

  • 函数需要修改实参的值时,使用指针可读性低而且不够安全。

const修饰---------------------------------------------------------------------------------

  • 大对象,可以使用const指针或const引用。
  • 如果传递对象是类对象,使用const引用,类设计常常要求使用引用。
何时使用值传递
  • 传小对象。

  • 如果对象是数组,则使用指针,这是唯一选择,并将指针用const修饰(使用const修饰是为了防止函数内部意外修改数组的内容(保护实参数组)。

相关推荐
8Qi81 分钟前
Redis哨兵模式(Sentinel)深度解析
java·数据库·redis·分布式·缓存·sentinel
饼干哥哥3 分钟前
聊了50个AI出海的市场团队,我总结了达人营销的7宗罪
前端
qq_427506085 分钟前
vscode使用kimi code的简单经验分享
前端·vscode·ai编程
恋猫de小郭6 分钟前
Claude Code 源码里有意思设定:伪造、投毒、卧底、封号
前端·人工智能·ai编程
wangchunting8 分钟前
数据结构-树
java·数据结构
无籽西瓜a11 分钟前
【西瓜带你学设计模式 | 第五期 - 建造者模式】建造者模式 —— 产品构建实现、优缺点与适用场景及模式区别
java·后端·设计模式·软件工程·建造者模式
wzl2026121314 分钟前
《基于企微会话存档的精准发送策略:从互动数据分析到防折叠群发》
java·数据分析·企业微信
Blurpath住宅代理20 分钟前
网页抓取(Web Scraping)完整技术指南:从原理到实战
前端
钰fly24 分钟前
Halcon联合编程适应图像的方法(picture)
开发语言·前端·javascript
木斯佳33 分钟前
前端八股文面经大全:字节跳动前端一面·深度解析(Plus Ultra版)(2026-03-30)·面经深度解析
前端·设计模式·八股·光栅化