【C++篇】启航——初识C++(下篇)

 接上篇【C++篇】启航——初识C++(上篇)

目录

一、引用

1.引用的概念

2.引用的基本语法

3.引用的特点 

3.1 别名

3.2 不占用额外内存

3.3 必须初始化

3.4 不能为 NULL

4.引用的使用 

4.1 函数参数传递

4.2 返回值

4.3 常量引用

5.引用和指针的关系 

(1).基本定义

(2).初始化

(3).改变指向

(4).访问对象

 (5).内存大小

(6).安全性

二、inline 

1.定义

2.使用方法

3.优点

4.注意事项

5.适用场景

三、nullptr

总结


一、引用

1.引用的概念

引用(Reference)是 C++ 中的一种类型,它提供了一个变量的别名。引用并不是一种独立的数据类型,而是对已有变量的另一种视图。引用的声明使用 & 符号。
引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间,它和它引⽤的变量共⽤同⼀块内存空间。⽐如:⽔壶传中李逵,宋江叫"铁⽜",江湖上⼈称"⿊旋⻛";林冲,外号豹⼦头;

2.引用的基本语法

int a = 10;       // 定义一个整数变量
int &b = a;      // b 是 a 的引用

在上面的例子中,b 作为 a 的引用,ba 是同一个对象,修改 b 的值实际上会改变 a 的值。

3.引用的特点 

引用的特点:

1.别名:引用是一个变量的别名,对引用的所有操作实际上都是对原变量的操作。

2.不占用额外内存:引用不占用额外的内存空间,只是另一个指向相同内存地址的标识符。

3.必须初始化:引用在创建时必须初始化,并且一旦初始化后不可改变绑定的对象。

4.不能为 NULL:引用不能被赋值为 nullptr,必须引用一个有效的对象。

3.1 别名

引用是一个变量的别名。这意味着对引用的所有操作都是直接对其所引用的变量的操作。引用没有独立的内存空间,它只是在原变量的基础上提供了一个新的名字。

#include <iostream>int main() {int a = 42;        // 定义一个整数变量 aint &b = a;       // b 是 a 的引用std::cout << "a: " << a << ", b: " << b << std::endl; // 输出 a: 42, b: 42b = 100;          // 通过引用 b 修改 a 的值std::cout << "After changing b..." << std::endl;std::cout << "a: " << a << ", b: " << b << std::endl; // 输出 a: 100, b: 100return 0;
}

在这个示例中,ba 的引用,对 b 的修改直接影响 a,反之亦然。

3.2 不占用额外内存

引用本质上是一个别名,不会占用新的内存空间。它只是指向已有变量的地址。因此,引用操作不会增加内存的使用。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
int main()
{int a = 0;// 引⽤:b和c是a的别名 int& b = a;int& c = a;// 也可以给别名b取别名,d相当于还是a的别名 int& d = b;++d;// 这⾥取地址我们看到是⼀样的 cout <<"a:" << &a << endl;cout <<"b:" << &b << endl;cout <<"c:" << &c << endl;cout <<"d:" << &d << endl;return 0;
}

在这个例子中,a、b、c、d的地址相同,证明引用并不占用额外的内存空间。 

3.3 必须初始化

引用在创建时必须被初始化。它不能在声明后再被赋值或指向其他变量。这一特性使得引用在使用时更加安全,避免了指向无效对象的风险。

#include <iostream>int main() {int a = 5;// int &b; // 错误:引用必须在声明时初始化int &b = a; // 正确:b 在声明时被初始化为 astd::cout << "a: " << a << ", b: " << b << std::endl; // 输出 a: 5, b: 5return 0;
}

试图声明一个未初始化的引用 b 会导致编译错误,而在初始化时,引用可以安全地与一个变量绑定。 

3.4 不能为 NULL

引用不能被赋值为 nullptr,它必须引用一个有效的对象。这意味着引用在创建后始终是有效的,避免了指向空地址的风险。

#include <iostream>int main() {int a = 10;int &b = a; // 正确,b 引用 a// int &c = nullptr; // 错误:引用不能为 NULLstd::cout << "b: " << b << std::endl; // 输出 b: 10return 0;
}

试图将引用 c 赋值为 nullptr 会导致编译错误。这确保了引用始终指向有效的对象。

4.引用的使用 

4.1 函数参数传递

使用引用作为函数参数可以有效避免大对象的复制,从而节省内存和时间。通过引用传递参数,函数可以直接修改原始数据,而无需创建副本。

#include <iostream>void increment(int &num) {num += 1; // 直接修改原始数据
}int main() {int value = 5;increment(value); // 传递 value 的引用std::cout << "Incremented value: " << value << std::endl; // 输出 6return 0;
}

在这个示例中,increment 函数接受 num 的引用,对 num 的修改直接影响 value,避免了复制的开销。

4.2 返回值

C++ 中的函数可以返回引用,这样可以在函数外部直接修改原始数据。这种方式在某些情况下可以提高效率,但需要谨慎使用,尤其是返回局部变量的引用是危险的。

#include <iostream>int& getReference(int &x) {return x; // 返回 x 的引用
}int main() {int a = 10;getReference(a) = 20; // 直接修改 astd::cout << "Updated value: " << a << std::endl; // 输出 20return 0;
}

4.3 常量引用

常量引用(const 引用)允许我们通过引用访问变量,但不允许修改它。这在需要保护数据不被意外修改时非常有用,尤其是在传递大型对象时,可以避免复制并保护原始数据。

#include <iostream>void printValue(const int &num) {std::cout << "Value: " << num << std::endl; // 只读操作
}int main() {int a = 10;printValue(a); // 输出 10printValue(20); // 可以传递字面量,输出 20return 0;
}

在这个例子中,printValue 函数接受 const int &num 作为参数,意味着它只能读取 num 的值,而不能修改。这样不仅保证了数据的安全性,还避免了复制的开销。

5.引用和指针的关系 

引用和指针是 C++ 中两个重要的概念,它们都可以用于间接访问变量,但在语法、功能和使用方式上存在显著差异。下面将从几个方面比较它们。

(1).基本定义

引用引用是一个变量的别名,它指向一个已有变量,并且在创建时必须初始化。引用不占用额外的内存空间,只是原变量的另一个名称。

指针指针是一个变量,它存储一个地址,指向另一个变量的内存位置。指针在定义时不一定要初始化,可以在之后赋值。

(2).初始化

引用:在定义引用时,必须立即初始化并引用一个有效的对象。一旦绑定到某个变量后,就无法改变引用的对象。

int a = 10;
int &b = a; // 必须初始化

指针:指针在定义时不需要初始化,可以稍后赋值。指针可以随时指向不同的对象。q

int *p; // 不初始化,指向未知
int a = 10;
p = &a; // 指向 a

(3).改变指向

引用:引用一旦初始化后,就不可以再改变引用的对象。

int a = 10;
int &b = a;
// b = 20; // 这将改变 a 的值为 20,但 b 仍然引用 a

指针:指针可以在程序运行时动态改变指向的对象。 

int a = 10;
int b = 20;
int *p = &a; // p 指向 a
p = &b;      // p 现在指向 b

(4).访问对象

引用:可以直接使用引用访问所引用的对象,语法上更简洁。

int a = 10;
int &b = a;
std::cout << b; // 直接访问

 指针:需要使用解引用操作符 * 访问指针指向的对象。

int a = 10;
int *p = &a;
std::cout << *p; // 解引用访问

 (5).内存大小

引用:在 sizeof 运算中,引用的结果是引用对象的大小,不占用额外的内存。

int a = 10;
int &b = a;
std::cout << sizeof(b); // 输出 sizeof(int)

指针:在 sizeof 运算中,指针的大小是固定的(在 32 位平台上通常为 4 字节,64 位平台上为 8 字节)。

int *p;
std::cout << sizeof(p); // 输出 4 或 8

(6).安全性

引用:因为引用不能为 NULL,也不会出现悬挂引用的问题,所以相对更安全。

指针:指针容易出现空指针和悬挂指针的问题,需要额外的小心和处理。

int *p = nullptr; // 空指针
// int a = *p; // 会导致未定义行为

二、inline 

1.定义

inline是C++中的一个关键字,主要用于建议编译器在调用函数的地方直接插入该函数的代码,而不是通过常规的函数调用。这通常用于小型函数,以减少函数调用的开销。

2.使用方法

在C++中,使用inline非常简单。你只需在函数定义前加上inline关键字。例如:

inline int add(int a, int b) {return a + b;
}

3.优点

  1. 性能提升:通过减少函数调用的开销(如压栈、弹栈等),可以提高程序性能,尤其是在频繁调用的小函数中。
  2. 代码可读性:小函数的使用使得代码更加模块化和易于理解。

4.注意事项

  1. 编译器的决定:虽然你可以建议编译器使用inline,但编译器并不一定会接受这个建议。它可能根据函数的复杂度和其他因素决定是否进行内联。
  2. 代码膨胀:如果一个inline函数被多次调用,编译器会在每个调用点插入函数体,可能导致代码膨胀,增加最终二进制文件的大小。
  3. 调试困难:内联函数在调试时可能会使得调用栈不如预期,因为调用点会被替换为函数体。

5.适用场景

  • 短小函数:适合将那些逻辑简单、体积小的函数标记为inline
  • 频繁调用的函数:例如,在循环中频繁调用的简单函数,使用inline可能会有显著性能提升。

三、nullptr

NULL实际是⼀个宏,在传统的C头⽂件( stddef.h )中,可以看到如下代码:
#ifndef NULL#ifdef __cplusplus#define NULL 0#else#define NULL ((void *)0)#endif
#endif
C++中 NULL 可能被定义为字⾯常量0,或者C中被定义为⽆类型指针( void* )的常量。不论采取何种定义,在使⽤空值的指针时,都不可避免的会遇到⼀些⿇烦,本想通过 f(NULL) 调⽤指针版本的
f(int*) 函数,但是由于 NULL 被定义成0,调⽤了 f(int x) ,因此与程序的初衷相悖。 f((void*)NULL) ;
调⽤会报错。
C++11中引⼊ nullptr nullptr 是⼀个特殊的关键字, nullptr 是⼀种特殊类型的字⾯量,它可以转换
成任意其他类型的指针类型。使⽤ nullptr 定义空指针可以避免类型转换的问题,因为 nullptr 只能被
隐式地转换为指针类型,⽽不能被转换为整数类型。
#include<iostream>
using namespace std;
void f(int x)
{cout << "f(int x)" << endl;
}
void f(int* ptr)
{cout << "f(int* ptr)" << endl;
}
int main()
{f(0);// 本想通过f(NULL)调⽤指针版本的f(int*)函数//但是由于NULL被定义成0,调⽤了f(int x),因此与程序的初衷相悖。 f(NULL);f((int*)NULL);// 编译报错:“f”: 2 个重载中没有⼀个可以转换所有参数类型 // f((void*)NULL);f(nullptr);return 0;
}

总结

引用、内联函数和 nullptr 是 C++ 中的重要特性,它们在代码的可读性、性能和安全性上都有显著影响。了解并合理使用这些特性,有助于编写出高效且可维护的代码。希望这篇博客对你有所帮助!如果有任何问题或想法,欢迎在评论区交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/55110.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站建设公司如何选?2024专业网站建设公司哪家好TOP3

要找一家靠谱的网站建设公司&#xff0c;可以根据以下五点判断&#xff1a; 1.企业的工商信息 企业有多少人、什么时候成立的、成立资金是多少、是否有违约记录这些都可以在查企业的那种app里可以看到&#xff0c;去查的时候一定要仔细甄别&#xff0c;别最后找了一家皮包公司…

PCL 索引空间采样

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 索引空间采样 2.1.2 可视化原始点云和下采样后的点云 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xf…

软件设计师——计算机网络

&#x1f4d4;个人主页&#x1f4da;&#xff1a;秋邱-CSDN博客☀️专属专栏✨&#xff1a;软考——软件设计师&#x1f3c5;往期回顾&#x1f3c6;&#xff1a;&#x1f31f;其他专栏&#x1f31f;&#xff1a;C语言_秋邱 一、OSI/ RM七层模型(⭐⭐⭐) ​ 层次 名称 主要功…

【Iceberg分析】调研Iceberg中表的原地演变

调研Iceberg中表的原地演变 文章目录 调研Iceberg中表的原地演变原生非分区表文件关系图表的原地演变之表schema演变新增字段new_column文件关系变化图为新增字段写入数据文件关系变化图删除新增字段文件关系变化图新增字段new_column2文件关系变化图删除数据文件关系变化图 原…

C++ | Leetcode C++题解之第433题最小基因变化

题目&#xff1a; 题解&#xff1a; class Solution { public:int minMutation(string start, string end, vector<string>& bank) {int m start.size();int n bank.size();vector<vector<int>> adj(n);int endIndex -1;for (int i 0; i < n; i)…

爬虫及数据可视化——运用Hadoop和MongoDB数据进行分析

作品详情  运用Hadoop和MongoDB对得分能力数据进行分析&#xff1b;  运用python进行机器学习的模型调理&#xff0c;利用Pytorch框架对爬取的评论进行情感分析预测&#xff1b;  利用python和MySQL对网站的数据进行爬取、数据清洗及可视化。

快速实现AI搜索!Fivetran 支持 Milvus 作为数据迁移目标

Fivetran 现已支持 Milvus 向量数据库作为数据迁移的目标&#xff0c;能够有效简化 RAG 应用和 AI 搜索中数据源接入的流程。 数据是 AI 应用的支柱&#xff0c;无缝连接数据是充分释放数据潜力的关键。非结构化数据对于企业搜索和检索增强生成&#xff08;RAG&#xff09;聊天…

SpringBoot框架下体育馆管理系统的构建

1引言 1.1课题背景 当今时代是飞速发展的信息时代。在各行各业中离不开信息处理&#xff0c;这正是计算机被广泛应用于信息管理系统的环境。计算机的最大好处在于利用它能够进行信息管理。使用计算机进行信息控制&#xff0c;不仅提高了工作效率&#xff0c;而且大大的提高了其…

江协科技STM32学习- P19 TIM编码器接口

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

Redis篇(Java操作Redis)

目录 讲解一&#xff1a;简介 讲解二&#xff1a;Jedis Github 一、创建项目、 二、添加依赖 三、配置文件 四、Java连接Redis 五、通过Redis连接池获取连接对象并操作服务器 六、封装JedisUtil对外提供连接对象获取方法 七、Java操作Redis五种数据类型 1. 连接与释放…

助农小程序|助农扶贫系统|基于java的助农扶贫系统小程序设计与实现(源码+数据库+文档)

助农扶贫系统小程序 目录 基于java的助农扶贫系统小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 5.1.1 农户管理 5.1.2 用户管理 5.1.3 订单统计 5.2.1 商品信息管理 5.3.1 商品信息 5.3.2 订单信息 5.3.3 商品评价 5.3.4 商品退货 四、数据库设计 1、…

水波荡漾效果+渲染顺序+简单UI绘制

创建场景及布置 创建新场景Main,在Main场景中创建一个plane物体&#xff0c;命名为WaterWavePla,具体数值及层级面板排布如下&#xff1a; 编写脚本 创建一个文件夹&#xff0c;用于存放脚本&#xff0c;命名Scripts,创建一个子文件夹Effect,存放特效相关脚本&#xff0c;创建…

WAF,全称Web Application Firewall,好用WAF推荐

WAF&#xff0c;全称Web Application Firewall&#xff0c;即Web应用防火墙&#xff0c;是一种网络安全设备&#xff0c;旨在保护Web应用程序免受各种Web攻击&#xff0c;如SQL注入、跨站脚本&#xff08;XSS&#xff09;、跨站请求伪造&#xff08;CSRF&#xff09;等。 WAF通…

前端面试经验总结2(经典问题篇)

谈谈你对前端的理解 前端主要负责产品页面部分的实现&#xff0c;是最贴近于用户的程序员。 基本工作要求&#xff1a; 1.参与项目&#xff0c;通过与团队成员&#xff0c;UI设计&#xff0c;产品经理的沟通&#xff0c;快速高质量的实现效果图&#xff0c;并能够精确到1px 2.做…

数学建模研赛总结

目录 前言进度问题四分析问题五分析数模论文经验分享总结 前言 本文为博主数学建模比赛第五天的内容记录&#xff0c;希望所写的一些内容能够对大家有所帮助&#xff0c;不足之处欢迎大家批评指正&#x1f91d;&#x1f91d;&#x1f91d; 进度 今天已经是最后一天了&#xf…

COMP 6714-Info Retrieval and Web Search笔记week2

tokenizer&#xff1a;分词器 右半部分&#xff1a;倒排索引 Westlaw AND&#xff08;&&#xff09;&#xff1a; 要搜索必须同时出现在文档中的两个或多个词语&#xff0c;请使用 AND&#xff08;&&#xff09;。例如&#xff0c;输入 narcotics & warrant&#x…

基于单片机的催眠电路控制系统

** 文章目录 前言一 概要功能设计设计思路 软件设计效果图 程序文章目录 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主…

【2024工业3D异常检测文献】CMDIAD: 基于跨模态蒸馏驱动的多模态工业异常检测

Incomplete Multimodal Industrial Anomaly Detection via Cross-Modal Distillation 1、Background 近年来&#xff0c;基于3D点云和RGB图像的多模态工业异常检测(IAD)研究强调了利用模态间的冗余性和互补性对于精确分类和分割的重要性。 在项目中&#xff0c;提出了CMDIAD方…

如何在算家云搭建MVSEP-MDX23(音频分离)

一、MVSEP-MDX23简介 模型GitHub网址&#xff1a;MVSEP-MDX23-music-separation-model/README.md 在 main ZFTurbo/MVSEP-MDX23-音乐分离模型 GitHub 上 在音视频领域&#xff0c;把已经发布的混音歌曲或者音频文件逆向分离一直是世界性的课题。音波混合的物理特性导致在没有…

js列表数据时间排序和取唯一值

1.取唯一值[...new Set(array)] const array [1, 2, 3, 2, 4, 5, 3, 5]; // 使用Set去除重复元素 const uniarray [...new Set(array)]; console.log(uniarray); // 输出: [1, 2, 3, 4, 5] 2.排序 var u [1,3,2,5,4]; var uu u.sort(); console.log(uu); var u [1,3…