C++:基础语法

news2024/11/23 10:14:25

一、命名空间

       在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://www.coloradmin.cn/o/1617424.html

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

相关文章

24V转2.8V2A降压芯片WT6030

24V转2.8V2A降压芯片WT6030 WT6030是一种高效同步整流降压开关模式转换器&#xff0c;集成内部功率MOSFET。该器件在宽输入电源范围内提供3A峰值输出电流&#xff0c;展现出卓越的负载和线路调节性能。其设计仅需要最小数量的外部现成组件&#xff0c;并且采用了节省空间的ESO…

GITHUB的VB代码无法加载的问题解决

GITHUB里有不少好的VB代码&#xff0c;但是下载之后&#xff0c;经常出现工程加载出错的问题&#xff0c;例如&#xff1a; LOG文件为&#xff1a; 不能加载 0 行 0: 不能加载文件 D:\xxxx\Semi VB API Loader\frmMain.frm 。 原因其实很简单&#xff0c;github里的换行符是u…

如何在PostgreSQL中使用索引覆盖扫描提高查询性能?

文章目录 解决方案1. 创建合适的索引2. 确保查询能够使用索引覆盖扫描3. 调整查询以利用索引覆盖扫描4. 监控和调优 示例代码1. 创建索引2. 编写查询3. 检查是否使用索引覆盖扫描4. 调整索引 总结 在PostgreSQL中&#xff0c;索引是提高查询性能的关键工具之一。索引允许数据库…

C# 字面量null对于引用类型变量✓和值类型变量×

编译器让相同的字符串字面量共享堆中的同一内存位置以节约内存。 在C#中&#xff0c;字面量&#xff08;literal&#xff09;是指直接表示固定值的符号&#xff0c;比如数字、字符串或者布尔值。而关键字&#xff08;keyword&#xff09;则是由编程语言定义的具有特殊含义的标…

积极探索新质生产力,九河云携手华为云技术交流引领数智跃迁

4月18日&#xff0c;九河云携手华为云举办了华为云SA技术培训会议&#xff0c;培训邀请到华为云技术人员作为主讲人&#xff0c;通过理论讲解与案例结合的方式&#xff0c;围绕ECS和EBS之间的联动&#xff0c;调优和数据保护等方面展开&#xff0c;深入浅出地讲解了基于EBS部署…

Python从0到100(十四):高级函数及函数使用进阶

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

【机器学习】分类与预测算法的评价与优化

以实际案例解析F1值与P-R曲线的应用 一、分类算法与性能评价的重要性二、F1值与P-R曲线的概念与意义三、实例解析&#xff1a;以垃圾邮件检测为例四、代码实现与结果分析五、结论与展望 在数据驱动的时代&#xff0c;机器学习算法以其强大的数据处理和分析能力&#xff0c;成为…

day07 51单片机-18B20温度检测

18B20温度检测 1.1 需求描述 本案例讲解如何从18B20传感器获取温度信息并显示在LCD上。 1.2 硬件设计 1.2.1 硬件原理图 1.2.3 18B20工作原理 可以看到18B20有两根引脚负责供电&#xff0c;一根引脚负责数据交换。18B20就是通过数据线和单片机进行数据交换的。 1&#xf…

PROSAIL模型前向模拟与植被参数遥感提取代码实现

原文链接&#xff1a;PROSAIL模型前向模拟与植被参数遥感提取代码实现https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247602140&idx7&sn7c4ca9239865d536ba81ba4c26a34031&chksmfa820e3bcdf5872d540c0dfe8c533c8696c8b4658427aab254f246a739f96b36bc37…

GPT 在目标设定中的应用:实现梦想的技术方法

在技术快速进步的时代&#xff0c;我们设定和实现目标的方式正在不断发展。 该领域最重要的创新之一是引入生成式预训练 Transformer (GPT)。 本文将探讨 GPT 技术如何彻底改变目标设定的艺术&#xff0c;提供实用的见解和案例研究来展示其影响。 GPT 和目标设定简介 ​ 了解 …

Ansible安装基本原理及操作(初识)

作者主页&#xff1a;点击&#xff01; Ansible专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月23日15点18分 Ansible 是一款功能强大且易于使用的IT自动化工具&#xff0c;可用于配置管理、应用程序部署和云端管理。它使用无代理模式&#xff08;agentles…

控制台居然可以这么玩?五分钟带你上手ANSI指令,实现一个log工具包

目录 前言 基础知识 进阶实践 ANSI参数 ANSI类 JSLog类 工具的使用说明 配置相关 全局配置项 默认配置 基本用法 打印字符 添加全局配置项 清空所有样式及操作行为 校验传入的参数是否正确 样式控制 Node环境 浏览器中 光标控制指令 光标位置偏移 滚动条控…

Pytorch:张量的梯度计算

目录 一、自动微分简单介绍1、基本原理2、梯度计算过程3、示例&#xff1a;基于 PyTorch 的自动微分a.示例详解b.梯度计算过程c.可视化计算图 4、总结 二、为什么要计算损失&#xff0c;为何权重更新是对的&#xff1f;1、梯度下降数学原理2、梯度上升 三、在模型中使用自动微分…

力扣HOT100 - 199. 二叉树的右视图

解题思路&#xff1a; 相当于层序遍历&#xff0c;然后取每一层的最后一个节点。 class Solution {public List<Integer> rightSideView(TreeNode root) {if (root null) return new ArrayList<Integer>();Queue<TreeNode> queue new LinkedList<>…

element中file-upload组件的提示‘按delete键可删除’,怎么去掉?

问题描述 element中file-upload组件会出现这种提示‘按delete键可删除’ 解决方案&#xff1a; 这是因为使用file-upload组件时自带的提示会盖住上传的文件名&#xff0c;修改一下自带的样式即可 ::v-deep .el-upload-list__item.is-success.focusing .el-icon-close-tip {d…

vue 关键字变红

1.html <div v-html"replaceKeywordColor(item.title)" ></div> 2.js //value为搜索框内绑定的值 replaceKeywordColor(val) {if (val?.includes(this.value) && this.value ! ) {return val.replace(this.value,<font color"red&…

PyCharm 中的特殊标记

再使用 PyCharm 开发 Python 项目的时候&#xff0c;经常会有一些特殊的标记&#xff0c;有些是编辑器提示的代码规范&#xff0c;有些则为了方便查找而自定义的标记。 我在之前写过一些关于异常捕获的文章&#xff1a;Python3 PyCharm 捕获异常报 Too broad exception clause…

【电控笔记5.8】数字滤波器设计流程频域特性

数字滤波器设计流程&频域特性 2HZ : w=2pi2=12.56 wc=2*pi*5; Ts=0.001; tf_lpf =

块存储、文件存储、对象存储概念与区别

1. 块存储 块存储是将数据切分成固定大小的块&#xff0c;然后将这些块存储在物理设备&#xff08;如硬盘、固态硬盘&#xff09;上。每个块都有唯一的标识符&#xff0c;并且可以独立地被读取、写入或删除。块存储通常用于存储文件系统&#xff0c;例如操作系统的文件系统&am…

牛客周赛 Round 40(A,B,C,D,E,F)

比赛链接 官方讲解 这场简单&#xff0c;没考什么算法&#xff0c;感觉有点水。D是个分组01背包&#xff0c;01背包的一点小拓展&#xff0c;没写过的可以看看&#xff0c;这个分类以及这个题目本身都是很板的。E感觉就是排名放高了导致没人敢写&#xff0c;本质上是个找规律…