C++的一些基础语法

前言:

本篇将结束c++的一些基础的语法,方便在以后的博客中出现,后续的一些语法将在涉及到其它的内容需要用到的时候具体展开介绍;其次,我们需要知道c++是建立在c的基础上的,所以c的大部分语法都能用在c++上。

1.域作用限定符

首先,认识一下域作用限定符:

#include <iostream>int main()
{
std::cout<<"hello world"<<std::endl;
return 0;}

代码中域作用限定符就是::,当我们遇到在用一个项目组中使用了相同的命名的时候,除了改该怎么办?我们可以指定对应的域中去找相应的重复命名的内容,例如去某个结构体或者类中去找(类在后面会介绍);其次记住一点,如果域作用限定符的左侧为空,就是去全局里面去找。

2.关键字namespace

#include <iostream>
using namespace std;
int main()
{cout<<"hello world"<<endl;return 0;
}

首先可以明显的看到,函数里面的内容少了点什么,这就是因为我们加上了一句using namespace std;,为什么呢?

这里就开始介绍初学c++为什么要这样写程序了,因为大部分人学会使用了c++却连开始为什么要这样写都说不上一二,就有些尴尬了,首先介绍开始的头文件:

我们查阅文档可知(来源:https://legacy.cplusplus.com/reference/)iostream中包含了cin和cout等(其实它们都是iostream的对象),所以我们要想使用cout和cin等就要包含这个头文件。

那cout和cin等又是什么?我们目前记住它们是用来显示屏幕的信息和提取屏幕的信息的,分别需要搭配流插入<<和流提取>>,所以它们就都相当于c中的printf和scanf,但是不同的是它们不是库函数,而是某个类的对象,后面再提,以及与printf,scanf的区别也在后面再提。

然后endl只需要知道它是换行的意思即可。

然后就是我们的命名空间这一行,这一行是什么意思呢?首先我们需要知道

  • 用法:namespace name

{}

  • 命名空间---命名空间域,只影响使用,不影响生命周期,在多个文件使用相同的命名空间会被认为是同一个

然后我们需要知道std是c++标准库的名字,也就是说如果我们想用封装在c++标准库中的内容就需要展开这个命名空间,也就是展开标准库所在的域,这样才能使用库中的内容,如果不这样使用,cout等就会不被编译器所认识。

但是需要注意,你会在一些人的代码中发现是这样写的:

std::cout<<"hello world"<<std::endl

为什么呢?首先我们知道了命名空间的存在其实就是为了封装起你写的内容,避免其他的重复命名出现导致出问题,而如果要让标准库中的域展开,那就破坏了这道防线,因为其实封装的目的就是防止你的命名与标准库中的冲突,再使用与标准库中同名的就不行了,所以就有了这样的写法(平时练习可以直接展开,但比较大的项目中不建议这样用)。

如果我们将上方的写法称为全部展开,那下面的写法就为部分展开:

using std::cout;
using std::endl;

也就是让比较常用的展开,避免一个一个写。

3.流插入和流提取

刚刚我们已经提到了它们,例如cout<<endl就是让换行符流到控制台上,再看一个流提取的例子:

int n=0;
double* a=(double*)malloc(sizeof(double));
if(a==NULL)
{perror("malloc fail");exit(-1);
}
for(int i=0;i<n;++i)
{cin>>a[i];
}
for(int i=0;i<n;++i)
{cout<<a[i]<<endl;
}

 这是一个输入数组元素,然后打印出来的例子,从中我们可以看到cout和cin的用法,但是我们也可以发现我们在使用cout和cin的时候好像不用管a是一个double类型的数组唉?

这就是流的特性:

  • 流会自动识别类型,不需要%d%f等输入输出

至于为什么,我们将在流的内容与运算符重载中在提。

4.缺省(默认)参数与缺省值

我们知道,在c语言中,函数的参数是不能赋值的,也就是说你传来的什么就是什么,而c++有创造了一个新的玩法:

	void func(int a=0){cout<<a<<endl;}int main(){func(1);//传参就是打印传的值,也就是1func();//不传就是打印默认值0return 0;}

至于有什么用,我们在以后再说(减少重载函数的数量,简化函数的调用过程)。

a.全缺省参数

全缺省就是所以参数都缺省:

void Func(int a = 10, int b = 20, int c = 30)
{cout << "a=" << a << endl;cout << "a=" << b << endl;cout << "a=" << c << endl;cout << endl;
}int main()
{Func(1, 2, 3);return 0;
}

需要注意的是,只能从右往左缺省,且要连续,为什么呢?

因为如果你要写成:

void Func(int a = 10, int b = 20, int c )

那你传两个参数的时候,c对应的位置必须要有一个传过来的参数(因为没缺省嘛),那第一个实参是对应的a还是b,不仅编译器会报错,意义也不明;参数从右往左缺省就不会出现这样的问题。

然后就是使用缺省值要从右往左(因为参数是从右往左缺省的)连续使用,像这样不连续的就不行:

Func(,1,2);

b.半缺省参数

也就是参数可以不完全缺省,规则也和全缺省一样(从右往左连续缺省),不同的是不能不传参数,如果传一个参数就是对应最左边的参数
 

c.注意
  • 不能在声明和定义中同时给缺省参数,要在声明中给(如果声明和定义的缺省值不同,编译器无法确定,放在声明中也减少了其他源文件重复定义;还有些人说是为了保护代码的安全,因为别人copy了源码却不知道缺省值)
  • 缺省值必须是常量或者是全局变量,c语言不支持缺省参数

5.函数重载

在c中,我们知道使用函数名相同的函数是行不通的,所以本贾尼博士又发明了一个新的语法,允许函数名可以相同,但是参数的个数或者返回类型或者类型的顺序要不同的同名函数存在。

void Add(int a,int b);
void Add(int a,int b,int c);void Add(int a,int b);
void Add(double a,double b);void Add(int a,int b);
void Add(int b,int a);

那具体是怎么实现相同的函数名能找到对应的函数呢?

c++对函数名进行了修饰(此为linux的修饰规则,不同平台的修饰规则不同),例如void Add(int a,int b),会修饰成_Z3Addii,void Add(double a,double b)会修饰成_Z3Adddd,其中_Z是固定的,3是函数名长度,再加上函数名,再加上形参的类型缩写,通过不同的函数名修饰加上编译时产生的地址,就能区别出调用哪个了(浮点数默认为double)

 另外还需要注意:

  • 返回值不同的,其他都相同,不构成重载,因为编译器识别不出来,不是因为修饰名没有返回值而识别不出,而是调用函数的时候没写返回值(call这个函数的地址的时候没有返回值),区分不出来
  • 编译时就已经确定了调用那个函数 ,编译速度可能变慢,但是运行速度不会变慢

6.指针和引用

a.语法

可以看到k是i的引用,并且地址是一样的,所以我们又说k是i的别名。

同时我们还可以看到,直接赋值地址是不一样的,因为是又开辟了新的栈帧。

引用在后面的应用有很大的作用。

注意:

  •  引用在定义时必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个实体,再不能引用其他实体

b.应用
  • 应用1(输出型参数)---实参影响形参的情况,例如改变实参的值就要传实参的地址,从而形参要用指针
	void Swap(int& x,int& y)//形参是实参的别名,地址一样,不用取地址{int tmp=x;x=y;y=tmp}
  • 应用2(做返回值)

首先,先引入传值返回:

我们可以看到:

返回的n先存到(拷贝给)一个临时变量(可能是寄存器也可能是上一层栈帧),然后count栈帧销毁,这个临时变量再给给ret,如果n是个静态的变量放在静态区,也是先存到临时变量,也不会直接返回n,此为传值返回(用于变量出了作用域就不在的情况)

如果使用传引用返回:

返回n的别名,减少了拷贝,因为n已经是静态的了,但返回时还要拷贝到一个临时变量,返回n的别名就减少了拷贝(可以理解产生了一个临时变量,但这个临时变量是n的别名,也就是n,就减少了拷贝 ),只要出了count作用域这个变量还在,就可以用传引用返回

所以使用传引用返回,我们可以得到以下结论:

  • 减少拷贝
  • 调用者可以直接修改返回的对象

我们再来看一个错误的例子:

int& Add(int a,int b)
{int c=a+b;return c; 
}int main()
{int ret=Add(1,2);//正确的int& ret=Add(1,2);//错误的
}

返回c的别名,ret又是c这块空间的别名,但是c这块空间销毁了,访问ret也是找到销毁的空间,如果c的空间被覆盖就是随机值,没有就还是那块空间

总结:

如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回(性能上有一定的提升),如果已经还给系统了,则必须使用传值返回,以此理解全局变量二者都可以(因为全局变量也是存在静态区的,所以也是先拷贝给临时变量)。

c.常引用

	const int c=2;const int& d=c;const int* p1=NULL;const int* p2=p1;const int m=1;int n=m;int count{int n=1;return n;}const int& ret=count();int i=0;const double& rd=i;

从前两个例子我们可以知道d是c的别名,c是不可改的,那d也应该是不可改的;同理指针也是(*p不能修改,但是p可以修改,需要根据const的位置,在c专栏中有介绍到这一点),

赋值或初始化,权限可以缩小(只有别名是const修饰),但是不能放大。

而第三个例子就仅仅赋值,所以n的改变不会影响到m。

第四个例子是count的返回值是n先拷贝给临时变量,再给ret,返回的这个临时变量(在此过程中)也不可改变,它的别名也要用const修饰。

第五个例子是隐式类型转换,类型转换会产生临时变量,i先给给double类型的临时变量,临时变量再给给rd,所以rd是这个临时变量的别名,而这个临时变量(因为在这个过程里面这个临时变量肯定不变嘛)具有常性,所以要加const。

d.指针和引用的区别

首先我们需要知道:

  • 从语法的角度,引用不开空间,指针需要开空间;而从底层的角度,从汇编来看二者过程一模一样,引用也是需要开空间的

其次不同点:

这里的安全是从引用没有空引用个定义必须初始化出发的,因为有时指针的一些错误不会直接报错。

7.内联函数inline

a.复习宏

c++推荐使用enum和const代替宏常量,inline代替宏函数。

我们来复习一下宏的优缺点:

优点:

  • 类型可以不固定
  • 不用建立栈帧

缺点:

  • 不能调试

  • 没有类型安全的检查

  • 有些场景非常复杂(例如add宏函数)

#define ADD(x,y)((x)+(y))

1.为什么x+y要加括号,因为宏只是替换,例如ADD(1,2)*3;不加括号就达不到效果了

2.为什么里面的x和y分别要加括号?因为例如ADD(a|b,a&b);宏会替换成a|b+a&b,而加号  

   优先级更高,也达不到想要的效果

3.加分号也不行ADD(1,2)*3;宏会替换成((1)+(2));*3;会报错

b.使用
	inline int Add(int x,int y){int z=x+y;return z;}

用汇编查看可知在调用内联函数时就展开了函数的逻辑,不用建立栈帧:

如果存在call Add就是没有展开函数,也就不是内联;红色箭头指向的就是没有call 这个函数的地址,直接展开函数体,使用了内联。 

c.内联函数的性质

关于第三点:
假设在头文件中声明一个内联函数,再在函数实现文件中定义一个内联函数,此时在主函数中使用内联函数就会链接报错,因为虽然主函数引用了头文件,但是内联函数是直接展开的,没有地址,头文件只定义了内联函数,但找不到内联函数的地址(也就是出现在了声明中,但是展开时找不到函数体),所以建议定义和声明都在头文件里。

注意:

如果成员函数在类中定义,编译器可能会将它当做内联函数处理。

所以在stl源码里面有些短小的函数直接就放在类里面定义了,就是当做了内联函数

有些大一点的函数就类中声明,类外定义,源码就这样搞的,所以声明定义分离还是有一定的道理的。

8.关键字auto

a.语法
int a=0;
auto b=a;
auto c=&a;cout<<typeid(b).name<<endl;//int
cout<<typeid(c).name<<endl;//int*

实际价值是为了简化类型很长的代码。

b.缺点
  • 不能做形参
  • 不能声明数组
  • 定义变量必须初始化 

c.特性
  • auto后加*或者&就是限定类型为指针或者是引用 
  • auto a=1,b=2;
    auto c=1,b=2.0;//报错

    同一行定义多个变量时,这些变量必须是相同的类型,否则编译器会报错,因为编译器是根据第一个类型进行推导,再用推导出来的类型定义其他的。

d.typedef的缺点(附加)
typedef char* pstring;
int main()
{const pstring p1;//报错,需要初始化const pstring* p2;//正确
}

 这里所说的缺点就是如果是const char* p1,就不会报错,因为const修饰的是p1指向的空间,可以不对p1赋初始值,但是使用typedef就不行了,这里会被误解为const char p1,const修饰的是p1,要对p1赋初始值。

9.范围for(c++11)

	int array[]={0,1,2,3};for(auto e:array)//自动依次数组中的数据赋值给e对象,自动判断结束,所以e的改{cout<<e<<" ";     //变不会改变数组的值,想改数组值用auto& e}cout<<endl;

c++11提供的语法糖,底层其实是迭代器,知道怎么使用就行(分号前是范围内用于迭代的变量,右边是被迭代的范围) 

这里auto加上了引用是因为数据量大且涉及深拷贝(以后还会介绍)。

10.关键字nullptr

c++里NULL(NULL是一个宏)被定义为0,识别出来是int,实际c++不定义应该是((void*)0)

总结:

只介绍了c++中一些常见的基础语法,精进需要结合后面的内容,毕竟只学习语法却不了解应用是学不好的,本文如有错误请指正并会及时回复。

 

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

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

相关文章

C#MQTT编程10--MQTT项目应用--工业数据上云

1、文章回顾 这个系列文章已经完成了9个内容&#xff0c;由浅入深地分析了MQTT协议的报文结构&#xff0c;并且通过一个有效的案例让伙伴们完全理解理论并应用到实际项目中&#xff0c;这节继续上马一个项目应用&#xff0c;作为本系列的结束&#xff0c;奉献给伙伴们&#x…

DDT+yaml实现数据驱动接口自动化

前言 在之前的文章中我们知道了yaml文件可以进行接口自动化。除了yaml文件&#xff0c;Excel文档也可以用来编写自动化测试用例。 一定很想知道这两者有什么区别吧&#xff1f; 1、Excel使用简单&#xff0c;维护难&#xff0c;多种数据类型转换起来比较复杂 2、yaml学习稍…

MySQL通过SQL语句进行递归查询

这里主要是针对于MySQL8.0以下版本&#xff0c;因为MySQL8.0版本出来了一个WITH RECURSIVE函数专门用来进行递归查询的 先看下表格数据&#xff0c;就是很普通的树结构数据&#xff0c;通过parentId关联上下级关系 下面我们先根据上级节点id递归获取所有的下级节点数据&#x…

Jenkins 节点该如何管理?

Jenkins 拥有分布式构建(在 Jenkins 的配置中叫做节点)&#xff0c;分布式构建能够让同一套代码在不同的环境(如&#xff1a;Windows 和 Linux 系统)中编译、测试等 Jenkins 的任务可以分布在不同的节点上运行 节点上需要配置 Java 运行时环境&#xff0c;JDK 版本大于 1.5 节…

2024春招算法打卡-腾讯WXG

大数相乘 class Solution {public String multiply(String num1, String num2) {String ZERO_STR "0";String ONE_STR "1";// 其中一个为0直接返回0if(ZERO_STR.equals(num1) || ZERO_STR.equals(num2)){return ZERO_STR;}// 其中一个为1直接返回另一…

C语言-写一个简单的Web服务器(一)

基于TCP的web服务器 概述 C语言可以干大事&#xff0c;我们基于C语言可以完成一个简易的Web服务器。当你能够自行完成web服务器&#xff0c;你会对C语言有更深入的理解。对于网络编程&#xff0c;字符串的使用&#xff0c;文件使用等等都会有很大的提高。 关于网络的TCP协议在…

zookeeper Study

zk介绍&#xff1b;一种分布式协调服务。 分布式锁&#xff0c;集群选举&#xff0c;数据同步 。 zk都能进行操作&#xff0c;redis&#xff0c;kafka&#xff0c;rabbitmq&#xff0c;都能够用zk做协调管理服务。关键时zk简单操作。 应用说明&#xff1a; 简单介绍一下流程 &…

芯片工程系列(2)传统封装(引线键合与裸片贴装)

英文缩写 Die&#xff1a;即为wafer上切割出来的芯片Wire Bonding&#xff1a;引线键合Dicing&#xff1a;晶圆切割Bias voltage&#xff1a;偏压lead frame&#xff1a;引线框架First Bond&#xff1a;一次键合Second Bond&#xff1a;二次键合PCB&#xff1a;印制电路板&…

JMH287亲测【鸣潮】一键内测风景端V1.0.2已整理并录制视频教学

资源介绍&#xff1a; 否需要虚拟机&#xff1a;否 文件大小&#xff1a;压缩包约15G 支持系统&#xff1a;win7、win10、win11 硬件需求&#xff1a;运行内存16G 4核及以上CPU独立显卡 资源截图&#xff1a; 下载地址&#xff1a; JMH287【鸣潮】一键端 [V1.0.2]

SpringMVC09、Ajax

9、Ajax 9.1、简介 AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 AJAX 是一种在无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术。 Ajax 不是一种新的编程语言&#xff0c;而是一种用于创建更好更快以及交互…

Spring Security的API Key实现SpringBoot 接口安全

Spring Security的API Key实现SpringBoot 接口安全 Spring Security 提供了各种机制来保护我们的 REST API。其中之一是 API 密钥。API 密钥是客户端在调用 API 调用时提供的令牌。 在本教程中&#xff0c;我们将讨论如何在Spring Security中实现基于API密钥的身份验证。 API…

CSP初赛备考—汉字与运算

汉字 英文字符 英文字符的编码有两种:①ASCII标准码,7位(128个字符)②ASCII扩展吗,8位(256个字符) 中文字符 汉字分为两级:①一级汉字:3755个,按汉语拼音字母的次序排列。②二级汉字:3008个,按偏旁部首排列。 那么,怎么编码呢?要使用区位码和字形码等等。 区…

【UE5】游戏框架GamePlay

项目资源文末百度网盘自取 游戏框架 游戏 由 游戏模式(GameMode) 和 游戏状态(GameState) 所组成 加入游戏的 人类玩家 与 玩家控制器(PlayerController) 相关联 玩家控制器允许玩家在游戏中拥有 HUD&#xff0c;这样他们就能在关卡中拥有物理代表 玩家控制器还向玩家提供 …

在centos7系统中如何给docker配置代理

一、需求场景 生产环境私有云中&#xff0c;通常一个集群的机器中只有几台机器可以直接访问公网&#xff0c;其他机器需要通过代理的方式从能访问公网的机器出去&#xff0c;在已经做了如下配置之后&#xff0c;使用docker pull命令已经报错超时timeout&#xff0c;这时可以尝…

利用tree命令自动保存文件层级结构

tree命令的使用 为了将上图左侧的文件目录&#xff0c;生成上图右侧中的文件夹结构列表&#xff0c;保存在txt中&#xff0c;使用了如下cmd命令&#xff1a; C:\armadillo-12.8.0>tree .>list.txt以上tree命令分为3部分&#xff1a; tree 命令. 在当前目录>list.tx…

02hadoop伪分布式搭建

3. 环境安装 3.1 安装方式 单机模式 只能启动MapReduce 伪分布式 能启动HDFS、MapReduce 和 YARN的大部分功能 完全分布式 能启动Hadoop的所有功能 3.2 安装JDK 3.2.1 JDK安装步骤 下载JDK安装包&#xff08;下载Linux系统的 .tar.gz 的安装包&#xff09; https://www…

循序渐进丨MogDB 数据库特性之动态数据脱敏机制

数据脱敏是行之有效的数据库隐私保护方案之一&#xff0c;可以在一定程度上限制非授权用户对隐私数据的窥探。动态数据脱敏机制是一种通过定制化脱敏策略来实现对隐私数据保护的技术&#xff0c;可以在保留原始数据的前提下有效地解决非授权用户对敏感信息访问的问题。当管理员…

稀碎从零算法笔记Day10-LeecCode:赎金信

题型&#xff1a;哈希表、字符串 链接&#xff1a;383. 赎金信 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以…

Cloud-Sleuth分布式链路追踪(服务跟踪)

简介 在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败 GitHub - spring-cloud/spring-cloud-sl…

文案高手不能说的秘密,拿来就用的文案素材库

一、素材描述 本套文案素材&#xff0c;大小58.20M&#xff0c;共有43个文件。 二、素材目录 &#xff08;一&#xff09;、一阶文案库 01.1-文案写作行业&#xff1a;年入百万文案高手的赚钱朋友圈&#xff01;.pdf 02.2-个人品牌创业&#xff1a;全网顶流个人品牌大咖都…