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);//传参就是打印传的值,也就是1
	func();//不传就是打印默认值0
	return 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++中一些常见的基础语法,精进需要结合后面的内容,毕竟只学习语法却不了解应用是学不好的,本文如有错误请指正并会及时回复。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

妇女节:打开AI视界,成就“她力量”

根据国内招聘平台猎聘发布的《2024女性人才数据洞察报告》&#xff0c;从2023年3月到2024年2月&#xff0c;女性在AIGC领域的求职人次同比增长了190.49%。随着人工智能时代的降临&#xff0c;女性正以前所未有的姿态&#xff0c;在技术的助力下&#xff0c;蜕变成为新生的力量。…

STM32电源及时钟介绍

一、STM32最小系统 二、电源电路 2.1供电电压VDD&#xff0c;VSS F103VET6 的引角图 在 F103VET6 的引角图中可找到 49\50 角&#xff0c; 74\75 角&#xff0c; 99\100 角&#xff0c; 27\28角&#xff0c;10 \11角一共 5 对的VDD&#xff0c;VSS&#xff0c;也就是给我们芯片…

鸿蒙开发学习入门教程之环境配置

最近鸿蒙开发越来越火&#xff0c;各个大厂都有鸿蒙版本的计划和宣传&#xff0c;看这个趋势&#xff0c;可能会在几年内发展壮大&#xff0c;为我们移动端码农开辟一片新的职场。所以现在开始学起来还是很有必要的。今天就一起开始配置环境搞起来吧。 首先&#xff0c;找到官…

高级语言讲义2010软专(仅高级语言部分)

1.编写一程序&#xff0c;对输入的正整数&#xff0c;求他的约数和。 如&#xff1a;18的约数和为1236939 #include <stdio.h>int getsum(int n){int i,sum0;for(i1;i<n;i)if(n%i0)sumi;return sum; } int main(){int sum getsum(18);printf("%d",sum); …

ERP实施顾问面试题目

02什么是BOM和ECN&#xff1f;它们的完整英文拼写是什么&#xff1f;什么是替代料&#xff1f;&#xff08;10分&#xff09; BOM物料清单是英文Bill of Material的简写&#xff1b;ECN工程变更通知单是英文Engineering Change Notice的简写&#xff1b;替代料&#xff1a;由于…

CPP编程-CPP11中的内存管理策略模型与名称空间管理探幽(时隔一年,再谈C++抽象内存模型)

CPP编程-CPP11中的内存管理策略模型与名称空间管理探幽 CPP的四大内存分区模型 在 C 中&#xff0c;**内存分区是一种模型&#xff0c;用于描述程序运行时内存的逻辑组织方式&#xff0c;但在底层操作系统中&#xff0c;并不存在严格意义上的内存分区。**操作系统通常将内存分…

08 数据结构之查找-Hash、二分、顺序

引言&#xff1a; 实现链式哈希的代码 /* 质数&#xff1a; 对于大于1的正自然数&#xff0c; 处理1和它本身别的数都无法整除它&#xff0c; 这个数就是质数 hash函数的确定&#xff1a; α(质量因子) 0.7-0.8比较合适 m&#xff1a;存储数据的真实个数 n&#xff1a;存储空…

H264解码器实现-帧间预测

前言 本文所说的帧间预测是指根据当前预测块的MV向量和预测所需的参考块数据&#xff0c;计算出当前预测块的预测像素值的过程。该过程得到的预测像素值经过运动补偿后&#xff08;与反变换量化之后得到的残差像素值相加&#xff09;可以得到滤波前的重建像素值。 原理说明 …

<Linux> 初识线程

目录 前言&#xff1a; 一、什么是线程 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;线程理解 &#xff08;三&#xff09;线程与进程的关系 &#xff08;四&#xff09;简单实用线程 &#xff08;五&#xff09;重谈虚拟地址空间 1. 页表的大小 2…

ARMv8/ARMv9架构入门到精通-学习方法

目录 1、学习ARM基础知识2、学习ARM异常(中断)3、学习MMU4、学习Cache5、学习Trustzone和安全架构6、学习ARM架构和各类IP推荐 本文转自 周贺贺&#xff0c;baron&#xff0c;代码改变世界ctw&#xff0c;Arm精选&#xff0c; 资深安全架构专家&#xff0c;11年手机安全/SOC底层…

WorldView卫星遥感影像数据/米级分辨率遥感影像

目前世界上最常用的高分辨率卫星影像莫过于WORLDVIEW系列了&#xff0c;在卫星遥感圈内可谓大名鼎鼎&#xff0c;不仅具有超高的分辨率还具有其他高分辨卫星所不具有的8波段&#xff0c;风光无限。在分辨率方面目前只有WORLDVIEW3和WORLDVIEW4能够达到0.3米的分辨率&#xff0c…

【神经网络与深度学习】LSTM(Long Short-Term Memory)神经网络模型

概述 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种特殊的循环神经网络&#xff08;RNN&#xff09;结构&#xff0c;通常被用于处理和学习时间序列数据。因此&#xff0c;LSTM属于深度学习领域中的一种神经网络模型。 在深度学习中&#xff0c;LSTM被广泛应用于…

站库分离技术--反向代理技术-雷池云WAF-给自己搭建一个安全点的网站

文章目录 概要整体架构流程技术名词解释技术细节ssh-ubuntu服务器docker-映射-链接-通信nginx反代mysql设置数据库新密码 小结我的mysql映射目录我的wordpress映射目录 成果展示 概要 新买了一个云服务器&#xff0c;想搭建一个站库分离的wordpress为主的网站&#xff0c;采用d…

数据结构:图及相关算法讲解

图 1.图的基本概念2. 图的存储结构2.1邻接矩阵2.2邻接表2.3两种实现的比较 3.图的遍历3.1 图的广度优先遍历3.2 图的深度优先遍历 4.最小生成树4.1 Kruskal算法4.2 Prim算法4.3 两个算法比较 5.最短路径5.1两个抽象存储5.2单源最短路径--Dijkstra算法5.3单源最短路径--Bellman-…

CentOS 7安装MySQL及常见问题与解决方案(含JDBC示例与错误处理)

引言 MySQL是一个流行的开源关系型数据库管理系统&#xff0c;广泛应用于各种业务场景。在CentOS 7上安装MySQL后&#xff0c;我们通常需要使用JDBC&#xff08;Java Database Connectivity&#xff09;连接MySQL进行后端操作。 目录 引言 CentOS 7安装MySQL 使用JDBC连接My…

AI入门笔记(四)

深度学习是人工智能的一种实现方法。本文我将学习到的关于深度学习的代表卷积神经网络的数学结构分享给大家。 深度学习是重叠了很多层的隐藏层&#xff08;中间层&#xff09;的神经网络。我们以一个例题为例。 建立一个卷积神经网络&#xff0c;用来识别通过 66 像素的图像读…

基于VSCode安装Node.js开发环境

根据官网介绍&#xff0c;Node.js 是一个免费的、开源的、跨平台的JavaScript实时运行环境&#xff0c;允许开发人员在浏览器之外编写命令行工具和服务器端脚本. Node.js框架由于是采用JavaScript语法进行调用的&#xff0c;因此Node.js环境除了用来编写调试Node.js代码&#…

mybatis基础操作(三)

动态sql 通过动态sql实现多条件查询&#xff0c;这里以查询为例&#xff0c;实现动态sql的书写。 创建members表 创建表并插入数据&#xff1a; create table members (member_id int (11),member_nick varchar (60),member_gender char (15),member_age int (11),member_c…

视图【MySQL】

文章目录 概念操作视图创建视图查询视图更新视图删除视图 视图规则和限制 概念 MySQL 中的视图&#xff08;View&#xff09;是一个虚拟表&#xff0c;其内容由查询定义。视图本身不包含数据&#xff0c;这些数据是从一个或多个实际表中派生出来的&#xff0c;通过执行视图定义…

简单了解TCP/IP四层模型

什么是计算机网络&#xff1f; 计算机网络我们可以理解为一个巨大的城市地图&#xff0c;我们想从A地前往B地&#xff0c;其中要走的路、要避开的问题都交给计算机网络解决&#xff0c;直到我们可以正常的到达目的地&#xff0c;那么我们会把其中的过程抽象成一个网络模型&…