C++:基础语法

一、命名空间

       在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,
以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

1.定义

       定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对 { } 即可, { } 中即为命名空间的成员。命名空间本质上定义的是域。命名空间可以嵌套,也可以定义其他的命名空间。在多个文件中,可以同时定义同名的命名空间,编译器会将这些命名空间进行合并。

namespace mynamespace
{int a;int b;
}

2.使用

       命名空间有三种使用方式:

       (1)加作用域限定符

       在C/C++中,不同域可以定义同名变量,但是局部优先。‘:’为作用域限定符,假如我们要访问全局变量,只需在变量前加一个‘::’符号即可。

       编译器若要查找一个函数,它的默认查找的顺序是:先局部,再全局域。它不会主动到命名空间去找,除非我们加上作用域限定符之后才会进去查找。

       上图中,编译器现在在局部查找a变量,没有进入命名空间中。不加作用域限定符,就打印0,当加上作用域限定符时,编译器才会到我们指定的命名空间去找。

       (2)直接展开命名空间

       当我们需要重复调用一个命名空间里面的函数时,每一次调用我们就需要指定一下命名空间,多少有点麻烦。我们可以使用下面一条语句:

using namespace mynamespace;

       这条语句意为展开命名空间,意在指示编译器可以进入到这个命名空间去查找。当使用了这条语句之后,查找的优先级:局部>全局>=命名空间。在全局和命名空间同时存在同名函数或变量时,展开了命名空间之后,相当于把命名空间里面的东西释放到了全局中,如果之前全局域中存在了同名函数,那么就会报错。

       当两个命名空间同时展开时,若两个命名空间同时存在同名函数或变量时,编译器就会报错。因此,展开全部的命名空间是有风险的。

       (3)展开指定成员

       那么我们可以使用第三种方式:指定展开某一个。

using mynamespace::a;

       这条语句意为只展开某一个函数或变量,之后调用它时就不需再指定了。

       这种方法解决了直接展开命名空间时可能会引起的命名冲突的问题。

二、C++输入和输出

       在C语言中,我们使用printf、putchar、scanf等函数在屏幕上输出、输入数据,它需要包含stdio.h这个头文件,但是在C++中,我们使用cin、cout来输入、输出数据。

       其中c为console(控制台)的缩写,out为输出的缩写。在C++中,‘<<’这个符号为“流插入操作符”,endl 为 end line 的缩写,意为换行。在C++中,它多了许多智能的特性,编译器会自动识别变量的类型。当我们想要使用 cout 时,直接使用会报错,因为它在 iostream 中被封装到了一个名为 ‘std’ 的命名空间中。我们个人写代码时,可以直接将std展开,因为没人会和我们起冲突。但是在项目中,多个人参与进来时,尽量不要随意全部展开命名空间。

       当我们想要输入一些数据时,可以使用cin,意为从控制台中提取数据。‘>>’为流提取操作符。

       它的操作顺序是从左到右,输入两个数分别放在对应的变量中。

       当然我们也可以使用 printf 等C语言中的函数,iostream中也定义了这些函数。

三、缺省参数

       在C++中,对函数传参时也和C有所不同。它引入了一个新特性,我们可以不对它传值,那么编译器就会使用你默认设置的值。

       这个默认的值是在设计函数接受参数时设置的。当然也可以缺省多个值

       有一点就是不能跳跃着传参,也就是不能传a和c不传b,不能将b空过去,这样编译器会报错。上面是全缺省,也可以半缺省,但是必须是从右往左缺省,否则在调用的时候就会产生歧义,编译器不知道要将值传给谁。

       缺省参数在定义和声明不能同时出现。它只在声明处给。

四、函数重载

       在C语言中,在同一作用域是不允许同名函数出现的。但是在C++中,它可以在同一作用域中出现同名函数。它的名字可以相同,但是它的参数类型、参数个数、参数顺序需要不同,与参数名无关,当参数相同时,参数名不同,这两个函数不构成重载。当我们输入不同的参数时,编译器会自动去匹配参数类型然后调用相应的函数。若两个同名函数定义在了两个命名空间中,我们把这两个命名空间展开,调用这两个函数时,编译器会报错。因为两个函数不在同一个作用域中,不构成重载关系,编译器不会去匹配他们的类型。

       那么为什么C语言不支持重载呢?

       本质上来讲,是编译器对函数名的修饰不同。在C语言中,编译器不对函数名进行修饰,直接通过函数名来匹配。而在C++中,编译器会根据参数的不同对函数名进行不同的修饰,它们的名字可以相同,但是对它们进行的修饰不同,也就是说,在编译和连接之后,它们已经变成了不同名的函数。不同的编译器对函数名的修饰规则不同。

五、引用

1.引用的定义及使用

       在C++中,引入了引用的概念。引用与指针类似,但又不同于指针。

int main()
{int a = 0;int* b = &a;//指针int& c = a;//引用return 0;
}

       在第二条语句中,‘&’为取地址符,‘&a’表示取出变量a的地址,它是在C语言中使用的,而在C++中,它仍然可以使用。但是在C++中,‘&’还有另一个用法是引用,简单来说就是取别名。我们对c操作,实际上就是对a操作。它与指针的区别是不需要再添加解引用操作符 ‘ * ’ 了。它不仅可以对整形、浮点型变量取别名,也可以对指针变量取别名。

int*& e = b;

       对a的任意一个别名取地址,取到的都是a的地址,也就是说a的别名和a的地址都是相同的,a的别名是c,也可以对c取别名,也可以对c的别名取别名,本质还是a。

       在链表的学习中,有许多的函数需要传递二级指针,使用起来不太方便,那么我们就可以给指针取别名传给函数,就不需要再解引用二级指针来改变一级指针的值了,直接改变别名的值即可。

       引用一旦引用了一个变量,就不能再改变引用的对象。它没有空引用的概念。

2.引用和指针变量间引起的权限问题

       要注意,最初创建的变量的权限是最大的,如果最初创建的变量为可读不可写,那么它的引用的权限是不能大于它所引用的变量的,它最多只能可读可写。

        如图,我们使用b来引用经过const修饰的变量a,出现了报错,这就是权限的放大,引用的权限超过了它所指向的变量。a所引用的值是不能改变的,而b却可以改变,这就是权限的放大。

       当我们给b前面加上const时,此时b与a的权限相等,不会报错。

       指针也是如此,当我们写出下面的代码时,也会报错。

int main()
{int a = 0;const int* b = &a;int* c = b;return 0;
}

       这种也是权限的放大,const修饰的是指针指向的值,这个指针指向的值不能改变,而指针变量c也指向了这个值,却可以通过解引用的方式来修改,是权限的放大,因此编译器会报错。

       若const修饰的是整型变量,它不会引发权限放大的问题。

int main()
{const int a = 0;int b = a;b++;return 0;
}

       const修饰的是a的值,a的值不能被改变,但是不影响a赋值给b,b的值怎样改变与a无关,它们分别存储不同的空间,它们的改变不会相互影响。

       来看下面一段代码

       我们又创建了一个变量c来引用a,然后通过c来改变a,这时发现b的值也改变了,并且没有报错,这是因为const限制的只是它修饰的变量,即不能通过b来改变,但是可以改变c的值来间接改变b的值。

       来看下一段代码:

int main()
{double a = 13.14;//const int b = a;int& c = a;
}

       这段代码也是会报错,属于权限的放大。因为a在赋值给b时,由于类型的不同,复制之前就要先做类型转换,而类型转换具有常性,相当于经过了const修饰,这时候引用经过const修饰的变量,就是权限的放大。

       引用与指针的不同点:

       1.在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

       2.引用在定义时必须初始化,指针没有要求。

       3.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体。

       4.没有NULL引用,但有NULL指针。

       5.在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)。

       6.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小。

       7. 有多级指针,但是没有多级引用。

       8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理。

       9. 引用比指针使用起来相对更安全。

六、内联函数

       在一些函数中,需要调用许多次其他小函数,比如在排序中,要排几千万个数据,就要调用几千万次到几亿次的交换函数,但是每一次调用都要开辟对应的栈帧,开辟栈帧又是有消耗的,在C++中,有了内联函数的概念,它的意思是就是像交换函数这种小的函数但是需要调用的次数非常多,那么就直接将它展开在调用它的函数中,省去了开辟空间的消耗。它与C语言中的宏类似。但是它是由编译器自动实现的,C语言中还需要我们自己去实现一个宏函数,宏函数的实现很困难并容易出错,内联函数就很好的解决了这一点。

       特性:

       1.它是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。

       2.对于编译器而言只是一个建议,不同编译器关于内联函数实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用内联函数修饰,否则编译器会忽略内联函数特性。

       3.不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
 

七、auto关键字(C++11)

       auto是一种能够自动推到变量类型的关键字,当一个变量的类型难以拼写时,就可以使用auto代替。

int main()
{std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange","橙子" },{"pear","梨"} };std::map<std::string, std::string>::iterator it = m.begin();while (it != m.end()){//....}return 0;
}

       std::map<std::string, std::string>::iterator 是一个类型,但是该类型太长了,特别容易写错。

直接将它换成auto,非常方便。

       也可以使用typedef来给类型取别名, 但是也有缺陷。

       使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

       使用细则

       用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。

       auto*指定了它的对象必须是指针。

       当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

       auto不能推导的情况

       1. auto不能作为函数的参数
       2. auto不能直接用来声明数组
       3.auto在实际中最常见的优势用法就是C++11提供的新式for循环,还有lambda表达式等进行配合使用。

八、基于范围的for循环(C++11)

       对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范
围内用于迭代的变量,第二部分则表示被迭代的范围。

int main()
{int array[] = { 1, 2, 3, 4, 5 };//使用auto、int都可以,auto只是自动推导类型。for (auto e : array)cout << e << " ";return 0;
}

       范围for循环不能改变数组中的值,范围for循环是将数组临时拷贝一份然后遍历这个临时拷贝的数组。改变这个临时数组并不能改变数组中的值。

       注意:

       1.与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。
       2.for循环迭代的范围必须是确定的,对于数组而言,就是数组中第一个元素和最后一个元素的范围,即不支持在函数中对传过来的整形指针使用范围for遍历;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

       3.它只支持从头到尾遍历数组。

十、指针空值nullptr(C++11)

       NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

       可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{cout<<"f(int)"<<endl;
}
void f(int*)
{cout<<"f(int*)"<<endl;
}
int main()
{f(0);f(NULL);f((int*)NULL);return 0;
}

       程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。

       在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void*)0。

       注意:
       1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入
的。

       2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。

       3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

30V-STM32设计项目

30V-STM32设计 一、项目描述 (已验证) 基于STM32c8t6芯片设计的开发板&#xff0c;支持4-30V宽电压输入&#xff0c;串口模式自动下载功能&#xff0c;支持串口和STlink&#xff0c;方式下载程序 二、原理图介绍 电源电路采用了DCDCLDO电路&#xff0c;如果是外接DC头供电的话&…

BM25检索算法 python

1.简介 BM25&#xff08;Best Matching 25&#xff09;是一种经典的信息检索算法&#xff0c;是基于 TF-IDF算法的改进版本&#xff0c;旨在解决、TF-IDF算法的一些不足之处。其被广泛应用于信息检索领域的排名函数&#xff0c;用于估计文档D与用户查询Q之间的相关性。它是一种…

HarmonyOS开发实例:【图片编辑应用】

介绍 本篇Codelab通过动态设置元素样式的方式&#xff0c;实现几种常见的图片操作&#xff0c;包括裁剪、旋转、缩放和镜像。效果如图所示&#xff1a; 相关概念 [image组件]&#xff1a;图片组件&#xff0c;用来渲染展示图片。[div组件]&#xff1a;基础容器组件&#xff0…

学习Rust的第16天:泛型类型

泛型类型是减少代码重复的好方法&#xff0c;因此它们对性能有巨大的影响&#xff0c;通过利用Rust中的泛型类型&#xff0c;开发人员可以编写更通用和可重用的代码&#xff0c;同时保持类型安全和性能。这种方法不仅减少了冗余&#xff0c;还增强了代码的可维护性和可扩展性&a…

AI大模型探索之路-实战篇2:基于CVP架构-企业级知识库实战落地

目录 前言 一、概述 二、本地知识库需求分析 1. 知识库场景分析 2. 知识库应用特点 3. 知识库核心功能 三、本地知识库架构设计 1. RAG架构分析 2. 大模型方案选型 3. 应用技术架构选型 4. 向量数据库选型 5. 模型选型 三、本地知识库RAG评估 四、本地知识库代码落地 1. 文件…

服务器基础知识(1)

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;服务器❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 1、什么是服务器 服务器是计算机的一种&#xff0c;它比普通计算机运行更快、负载更高、价格更贵。服务…

WIFI/BT中蓝牙的硬件资源是如何调度的 UART和PCM接口传输的是什么信号

安卓或IOS手机中&#xff0c;wifi/bt中的蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。M.2 wifi/bt模块或其他形式的模块中&#xff0c;蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。今天我们就图文并茂的解决这个问题。 蓝牙文件…

MATLAB使用速成 第三章(MATLAB绘图)

一、二维平面作图 1、简单的x-y坐标图 x、y是长度相同的向量&#xff0c;以x的分量为横坐标&#xff0c;y的分量为纵坐标&#xff0c;作平面曲线&#xff0c;使用命令plot(x,y)。&#xff08;可以省略参数x&#xff0c;这样将会以y的分量下标为横坐标&#xff0c;y的分量为纵坐…

如何在极狐GitLab 中用 docker in docker 的方式使用 docker?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

C语言游戏实现——贪吃蛇

思路讲解 ** 贪吃蛇游戏是要求我们要操控一条蛇&#xff0c;在游戏规定的空间之内&#xff0c;进行吃食物&#xff0c;吃到一个就增加蛇身的长度&#xff0c;并且游戏得分加1&#xff0c;如果吃到自己&#xff0c;和碰到墙就算死亡&#xff0c;同时可以增加蛇的速度和减慢蛇的…

Python开源项目周排行 2024年第8周

#2024年第8周2024年4月12日1llama3当知无愧AI LLM领域当红炸子鸡&#xff01;Llama 3 是由 Meta AI 开发的大型语言模型 (LLM)&#xff0c;于 2024 年 4 月发布。它基于 Megatron-Turing NLG 模型架构&#xff0c;并在超过 15 万亿个标记的公开可用数据上进行了预训练&#xff…

算法训练营day15

一、层序遍历 参考链接7.2 二叉树遍历 - Hello 算法 (hello-algo.com) 层序遍历本质上属于广度优先遍历&#xff0c;也称广度优先搜索&#xff0c; BFS通常借助队列的先入先出的特性实现 参考链接102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; 像这种较为…

百度GL地图实现选点获取经纬度并且地址逆解析

index.html引入 <script src"https://api.map.baidu.com/api?typewebgl&v1.0&ak你的ak"></script>组件使用 <el-input:disabled"[详情].includes(title)"v-model"formData.site"placeholder""><templat…

【行为型模型】迭代器模式

一、迭代器模式概述 迭代器模式定义&#xff1a;提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露其内部的表示。把游走的任务放在送代器上&#xff0c;而不是聚合上。这样简化了聚含的接口和实现,也让责任各得其所。(对象行为型) 迭代器模式的优缺点&…

virtualbox 网络设置实现主机和虚拟机互相访问

前言 一般来说&#xff0c;virtualbox 虚拟机的上网模式是 NAT。这样虚拟机可以上网并访问宿主机&#xff0c;但宿主机无法访问虚拟机&#xff0c;也无法 ping 通。下面介绍双网卡模式&#xff0c;实现虚拟机和宿主机能够互相访问 ping 通。 双网卡模式 进入虚拟机的网络设置…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别 一、简单介绍 二、简单人脸识别实现原理 三、简单人脸识别案例实现简单步…

C语言—深度剖析函数指针,函数指针数组

我们先来看一段代码 #include <stdio.h> void test() {printf("hehe\n"); } int main() {printf("%p\n", test);printf("%p\n", &test);return 0; }输出的是两个地址&#xff0c;这两个地址是 test 函数的地址。 那我们的函数的地址…

杰理695的UI模式LED灯控制

UI模式LED灯修改每个模式对应的LED灯闪烁修改在ui_normal_status_deal(u8 *status, u8 *power_status, u8 ui_mg_para)

关系型数据库中primary key和foreign key、索引的作用

文章目录 一、关系型数据库中主键(primary key)和外键(foreign key)的概念。二、MySQL索引的作用(索引的优缺点)一、关系型数据库中主键(primary key)和外键(foreign key)的概念。 二、MySQL索引的作用(索引的优缺点) MySQL索引是一种数据结构,它可以提高查询性能…

MATLAB初学者入门(13)—— 遗传算法

遗传算法是一种受自然选择和遗传学启发的搜索启发式算法&#xff0c;用于解决优化和搜索问题。它模拟了自然界中生物的进化过程&#xff0c;包括基因的选择、交叉&#xff08;杂交&#xff09;和变异。 MATLAB 提供了一个方便的工具箱&#xff0c;即全局优化工具箱&#xff0c;…