C++感受2-逐字逐句,深入理解C++最小例程

news2024/11/27 2:39:02

以 “Hello World” 例程为载体、线索,在完成 “间接名字空间限定” 写法转换到“直接名字空间限定”的过程,同时掌握函数、主函数、函数调用、级联操作、声明、类型、int、字符串类型、头文件包含、行为数据、流输出操作符、标准输出流对象、标准库名字空间、ADL等20多个C++知识点,打好基础,让后续的学习事半功倍。

 0. 视频

逐行逐句深入讲解cpp最小例程

1. 函数

1.1 基本概念

在编程语言中,函数通常用于表达“做事情”的概念,它需要描述清楚做事情的三个要素:

  1. 做事情的“初始材料”
  2. 做事情的“操作过程”
  3. 做事情的“返回结果”

“初始材料”指对在做事情之前,需要从调用者处得到的数据的描述;
“操作过程”指对做事情的完整过程描述;
“返回结果”指对做事情可能得到的结果的描述;

除此之外,函数还有一个重要的外在属性:调用者。函数对应做事情,有时为了把“大事化小”,需要将一件大事,拆分成多个小事,然后再由大事调用小事(此处的“大”和“小”仅为相对概念,有时候“小”事也可能调用“大”事)。比如:“妈妈炒菜”是一件事,对应一个函数,在炒菜过程中,如果发现家里没有酱油了,炒菜无法进行下去,此时可以调用另一件事所对应的函数:“小明打酱油”。在这一例子中,“小明打酱油”函数的调用者,即“妈妈炒菜”函数。

1.2 基本语法

除此之外,函数还需要有名字,四者的组成语法为:

返回结果类型 函数名 ( 所需初始材料声明 )
{
       操作过程描述;
       return 返回数据;
}

其中:

  • “所需材料声明” 整体上构造函数的参数表(也称参数列表);
  • return 语句用于结束函数的操作过程(简称结束函数), “return” 正是 “返回”的意思;
  • 当一个函数声明为必须有返回结果时,对应的 return 语句后面也必须带相应类型的数据。

1.3 函数头、函数声明

三要素中的“初始材料”描述和“返回结果”描述,再加上函数名字,构成了“函数头”。如在函数后面直接加分号(语句分隔符),称为该函数的声明,即:对函数的基本约定,形如:

返回结果类型 函数名 ( 形参表 ); 

函数声明只是对函数所要做的事的基本描述和约定。即:描述了这件事的“入”和“出”:“入”是指需要“拿到”什么初始数据(材料),“出”是指事情完成后,可能返回什么结果数据。

对于同一个函数,函数声明可以多次出现。因此函数声明可视为一个人的“名片”。
函数声明有时也称为“函数原型”,意为:这个函数“大概长什么样子”。

1.4 函数体、函数定义

函数体用于实现函数,它是函数头之后的一对花括号,花括号内是实现具体操作过程的代码。
函数头加函数体,即代表了一个函数的真实实现。以下是一个真实的C++函数定义例子:

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

 它表示有一个函数,名为 “add”,它在执行之前,需要从调用者得到两个入参:a和b,二者的类型一个是整数类型,另一个也是整数类型。这个函数执行之后,也会返回(得到)一个整数数据。从实现上看,即返回 a+b 的结果。

一个函数应该只有一个真实实现,称为(函数的)定义。

2. 主函数

主函数可理解为:对应到整个程序需要做的那件“大事”。

主函数是一个特殊的函数。它的第一个特殊之处,即名字必须固定为 main,小写(C++代码区分大小写)。

主函数的第二个特殊之处,它的调用者是程序的外部运行环境,比如操作系统(但并不一定是操作系统,有些程序会运行在虚拟机内,也有些时候,程序由另一个程序调用)。

主函数之所以函数名需要固定,正是为了和外部环境,也就是它的调用是约定好:请将主函数视为程序的开始位置,因此主函数也时常被称为“入口函数”。

仅是“视为”,C++程序实际上仍然可以要求在进入主函数之前,就“偷偷”做点其它事情(通常用于准备工作)。

主函数也是函数,因此也需要考虑“初始材料”和“返回结果”。

既然调用者是外部运行环境,因此主函数如果需要获得初始材料,也是由外部运行环境传入,方法也正是主函数的参数列表。此处,主函数又有特殊之处,它的参数列表可以二选一:

  1. 不需要参数,即空的参数表;
  2. 需要参数,形如: (int argc, char* argv[]);
    我们在很长时间内,会仅使用第1种形式,因此暂不解释第2种形式。

C++主函数必须返回一个整数,因此在函数头中,需写明其返回数据的类型为整数类型,在C++中使用int(即 integer 缩写)。主函数返回的整数有以下含义:

  • 0:表示程序运行正常结束;
  • 非0:表示程序因出错而意外结束,各整数值可用于不同的错误编号。

在函数体中,主函数又有一个“特权”:可以不写任何 return 语句。该情况下表示该主函数永远执行正确,永远返回0。事实上,这个“特权”的背后,只是编译器在发现一个主函数没有返回语句时,就主动帮我们添加了 “return 0;” 而已。

再次强调:这是主函数的“特权”,其它函数如果在声明自己需要有返回值(哪怕返回的类型也是int)却不写(或忘记写) “return XXX;” 语句,会带来严重后果。

3. 认识“流”

上一节课我们所写的代码中,主函数的操作过程就句(事实上还有隐藏的一句“return 0;”):

cout << "Hello World" << endl;

3.1 cout - 标准输出流对象

这其中cout读作c-out,c 是 “character”,out 是 “output-device”,合起来意为“字符输出设备”,即 cout 对应者程序的输出屏幕。

当然,cout 仅用于windows下有控制台或linux/unix下拥有终端的程序,图形界面程序 GUI
的屏幕输出,有另外的实现机制。

由于C++的标准输入输出基于“流”的概念设计及实现,因此cout也称为C++的“标准输出流对象”。关于“流”的概念,本站《STL和boost之“流” 视频辅导》 课程有深入讲解。现在大家可以简单理解为,就像水流、电流一样,C++中的“流”就是将待输出或待输入的数据,排成一串,在某个“管道”中,按某个方向“流”动。

3.2 << - 流输出操作符

两个小于号组成的符号,称为C++的“流输出操作符”。
以小学所学的加号 + 类比:

  • 需要两个操作数、<< 也是;
  • 执行的操作是将左右两数相加,<< 执行的操作是将右边的数据,输出到左边的对象身上;
  • 的操作结果是相加之和那个数,<< 操作结果则是继续得到它左边的对象,在本例中,即 cout;
  • 支持级联操作,比如: 1+2+5,可先计算出 3,然后3继续参与计算: 3+5。<< 也支持级联操作: cout << "Hello World"后,得到的仍然是 cout,于是继续参与计算 cout << endl;

在C++中,操作符本质上也是一种函数。

3.3 endl - 操作控制符、“行为”数据

endl 也是一个函数,但此处我们将它当作数据使用,将它输出到 cout 身上。作用是将之前已经送到 cout 身上的数据,完完整整地送到真实的屏幕上,并加上换行。

每次往真实的显示屏幕上输出,比较耗性能(无关数据量);因此,为提高性能,输出的数据可能被cout对象“攒”起来,积累到一定程度再一次性真实输出。

3.4 ; - 语句分隔符(语句结束符)

在编辑器中,我们可以把一行的C++语句,拆成多行写,比如:

cout <<
    "Hello World"
    << endl;

通常仅在这一语句确实很长时使用,上面的例子显然是在强行换行,不推荐。

 也可以将多个语句合成一行(这就很不推荐了):

cout << "Hello World" << endl; return -1;

对于简单的独立语句,C++编译器都是通过分号来分隔前后两行语句。注意,哪怕如本例中只有一行语句,也需要使用。

反过来,也并不是所有形式语句都需要分隔,后面将学习到复合语句,就是使用一对 {} 包含多行简单语句,此时 {} 就是天然的分隔。在本例中你可以将函数体的那一对花括号视为一种复合语句。

更不是所有代码行都需要语句分隔符。比如本例中的第一行:

#include <iostream>

深入区分的话,这是一行“预处理”代码,“预处理”是指在正式编译之前,先读一下代码做一些比较基础的准备工作,因此这些代码不被视为正式的C++语句,如此,这些代码也被硬性按格式要求书写,比如上面的 include 就只能写在一行,不能折行,下面是错误示例:

#include 
     <iostream>

 

4 出处!出处!!出处!!!

和现实生活中一样,任何一件出处不明的物体,或者人物,都是危险的,所以请再看一眼代表做“大事情”的主函数代码:

int main()
{
  cout << "Hello World" << endl;
}

请问:cout 是谁? << 又是谁? endl 呢?这三个家伙来自哪里?也就是它们的可信出处是?
如果没有出处,严谨的C++编译器不会让这些代码通过编译;而,如果有出处,编译通过了,但程序执行后所要做的事,却不一定真的如我们前面辛苦解释那样的:往屏幕上输出一行对世界的问候——如果它们的出处是由“坏人”提供的话。

4.1 头文件 - 相关符号的统一出处

头文件就像家族族谱,或者松散一点,就像一个名片录或通讯录,可以记载许多符号(比如人名)的出处——在我们名片录或通讯录的人,确实比完全的陌生人,要安全那么一点点了。

#include <XXXX>

 这一行代码中 #include 是一种硬性规定,它是一行预编译代码,用于指示编译器:在你正式工作(正式开始编译当前源文件后续内容)之前,请先找到并打开XXXX文件(通常被称为“头文件”),读入其中的内容——因为这些内容对后续的编译工作有关键作用。

一对 <> 也是一种硬性规定,它进一步要求编译器:当你需要在电脑中成千上万的文件中搜索XXXX文件时,一!定!不!要!到!处!乱!翻!(怕你不小心翻到主人的各种学习资料),你只能在编译环境事情约定,或编译参数中配置好的文件夹里去寻找。

 

4.2 iostream 头文件

iostream 正是来自C++自带的标准库的一个头文件,主要是包含了和“流”相关的各种符号的声明。从字面上看:i 是 input / 输入 ,o 是 output / 输出,stream 就是 “流” 的英文单词。

iostream 正是包含我们在本例中用到的 cout 、<< 、endl 这三个符号的声明,于是这三者相当于了合法的出处:我们出自iostream文件,而后者出自C++自带的标准库,而当前机器上的C++标准库,就是你自己下载、安装到你的电脑上的。

当然,我们的课程用的是线上编程环境,因此iostream等文件,实际在网络所在后台服务器,我们当然也选择相信。

4.3 namespace 名字空间

代码中的各个符号(通常称为标识符)本质就是一个个名字,而一牵涉到名字,就和现实生活一样,会有重名的情况。C++可以“名字空间 / namespace”来避免重名,方法就是将所有相关的名字,统一放在一个“名字空间”内。正如视频所讲,学校中的每个班级,天生就是一个个名字空间,因此“三年一班的李国庆”和“四年二班的李国庆”就得以区分。

当然,这样的前缀,通常只需在两人出现在同一场合的情况下需要。另外,这也解决不了同一名字空间下的重名问题。

标准库也用到了大量的符号,并且它因为是“标准库”,所以就很霸道地占用了很多极为常用的符号名字,比如 “sort”、“find”、“search”、“string”、“begin”、“end”、“list” ……所以,标准库问世后,很快就给自己搞了一个名字空间:std (来自 standard)。

所以,前述的 cout、<<、endl,严格讲其实在 iostream 里声明的全称,解读起来应该是 std::cout、std::<<、std::endl。实际使用时,也应该用上这样的“全称”:

 std::cout std::<< "Hello World" std::<< std::end;

但是,为什么我们现在的代码:cout << “Hello World” << endl 可以编译并正确运行呢?这就是第三行代码的作用:

using namespace std;

它用来告诉编译器,如果在后面的代码,遇到实在找不到出处的符号,可以加上 std::再试试。以 cout 为例,当找不到它的出处时,可将它变成 std::cout 再尝试,于是就成功了。

4.4 关键字

并不是所有在代码中出现的符号都需要担心重名,C++语言(其它语言也一样)规定了一些特别重要的单词(符号)专门给自己使用,其他人(普通程序员)不能把这些单词随意拿作他用,自然,在如此“霸道”的规定下,这些单词就不会有重名的担心了。这样的单词就叫关键字/keyword。

本例中,int、using、namespace,以及被删除掉那一行的 return 都是C++的关键字,C++有近100个关键字。

iostream 则是用户(标准库作者)为文件取的名字,main也是(标准库)程序员为C++入口函数取的名字,std是标准库自用的名字空间的名字,它们要么来自标准库,要么是语言标准的硬性规定,显然我们在写代码时,为符号给的名字,还是尽量不要和它们重名的好。

4.5 直接名字空间限定

使用 using namespace XXX 的方法,称为“间接名字空间限定”,它会将XXX下的所有公开的符号名字,都引入当前代码下。这不是推荐的,名字空间的日常方法。我们的例程经常使用它,仅仅是因为我们的代码比较简单,而间接名字空间限定比较方便让代码行变短一些,从而有利于例程排版。

大多数情况下,我们推荐使用 “直接名字空间限定”的方法,下面就是使用这一方法的,新的Hello World 例程的完整代码:

#include <iostream>

int main()
{
    std::cout << "Hello World" << std::endl;
}

此时,cout 和 endl 都被直接加上 std:: ,相当于有一个特殊的前缀,直接接明它们来自std这个名字空间,又直观又安全。

  • 直观:把 :: 读成 “的”,就有: “std的cout”及“std的endl”,有如生活中的 “三年一班的李国庆”。
  • 安全:“间接名字空间限定”是在某一符号出处查找失败,才尝试使用间接指定的某个名字空间去套用,自然就有“套用”结果不是程序员本意的意外可能。直接名字空间限定出这种错误的可能性近乎零。

​4.5 ADL - 实参依赖查找

眼尖的同学会发现,在直接名字空间限定的写法中:

std::cout << "Hello World" << std::endl;

这行代码,只是用std::限定了 cout 和 endl,<< 却没有限定。

事实上,因为 << 是一个操作符,如果写作 std::<< 反倒会编译失败。
这就涉及到了 ADL(Argument-dependent lookup)这一语法知识点,它与编译规则也紧密相关。

 简单地说,和现实生活中类似,操作的对象,往往可以反过来帮助推导出操作的实际出处。比如“打屁股”、“打酱油”和“打车”的操作都是“打”,但其实各自含义大不相同(放在《辞海》里的出处自然也不同)。我们,也就是人类是通过打的对象,也就是“屁股”、“酱油”、“车” 倒过来推导出各自前面的“打”的含义。

编译器也有这样的智慧,它们也可以依据操作对象,倒过来推导操作的出处。比如:看到 << 这个操作符,因为没有加名字空间直接限定——事实上操作符的日常使用语法,也规定了不允许为它加名字空间前缀——而找不到其出处,自然无法知道它对应的真实操作……但是,编译器很快发现 << 所要操作的对象中,std::cout 是明确的,于是会到 std 这个名字空间下查找 <<,这就找到了,发现它是标准库的流输出操作符。

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

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

相关文章

LeetCode.2129. 将标题首字母大写

&#x1f354;题目 2129. 将标题首字母大写 &#x1f35f;分析 这道题目描述的很清晰&#xff0c;我们只需要将给定的字符串按照空格划分成字符串数组 str&#xff0c;然后判断 str[i] 的长度如果 <2 &#xff0c;则将 str[i] 转为小写&#xff0c;如果 str[i] 的长度 &g…

Python批量提取Word文档表格数据

在大数据处理与信息抽取领域中&#xff0c;Word文档是各类机构和个人普遍采用的一种信息存储格式&#xff0c;其中包含了大量的结构化和半结构化数据&#xff0c;如各类报告、调查问卷结果、项目计划等。这些文档中的表格往往承载了关键的数据信息&#xff0c;如统计数据、项目…

CSS 用 flex 布局绘制骰子

<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.box {height: 100px;width: 100px;border: 2px solid grey;border-radius: 10px;display: flex;justify-content: center; // 水平居中/* alig…

new-easy(pwn)

1.进行查壳 栈保护&#xff0c;三个保护都开了 NX保护 NX保护在Windows中也被成为称为DEP&#xff0c;是通过现代操作系统的内存单元&#xff08;Memory Protect Unit &#xff0c;MPU&#xff09;机制对程序内存页的粒度进行权限设置&#xff0c;其基本规则为可写权限与可执…

简述类与对象

一、两者关系 类是Java语言中最重要的数据类型&#xff0c;用于创建具体实例&#xff08;对象&#xff09; 抽象出一类事物共有的属性和行为&#xff0c;即数据以及数据上的操作 类是对现实事物的模拟&#xff0c;包含属性&#xff08;成员变量&#xff09;和行为&#xff0…

python读取大型csv文件,降低内存占用,提高程序处理速度

文章目录 简介读取前多少行读取属性列逐块读取整个文件总结参考资料 简介 遇到大型的csv文件时&#xff0c;pandas会把该文件全部加载进内存&#xff0c;从而导致程序运行速度变慢。 本文提供了批量读取csv文件、读取属性列的方法&#xff0c;减轻内存占用情况。 import pand…

2024.3.12 C++

1.思维导图 2.自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height),定义公有成员函数: 初始化函数:void init(int w, int h)更改宽度的函数:set_w(int w)更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show() #include <iostream…

python(ogr)处理geojson为本地shp文件

前言 本次所利用的geojson数据来自https://geo.datav.aliyun.com/areas_v3/bound/410000_full.json &#xff0c;如果觉得下方代码看起来不方便&#xff0c;可以来GitHub上来看&#xff0c;在这上面还有一些辅助内容便于理解 GISpjd/GIS-union-Python (github.com)https://gi…

【2024.03.12】定时执行专家 V7.2 发布 - TimingExecutor V7.2 Release

目录 ▉ 软件介绍 ▉ 新版本 V7.2 下载地址 ▉ V7.2 新功能 ▼2024-03-12 V7.2 - 更新日志 ▉ V7.x 新UI设计 ▉ 软件介绍 《定时执行专家》是一款制作精良、功能强大、毫秒精度、专业级的定时任务执行软件。软件具有 25 种【任务类型】、12 种【触发器】触发方式&#x…

Linux内核介绍and下载

Linux内核介绍and下载 介绍下载下载历史版本 我是将军我一直都在&#xff0c;。&#xff01; 介绍 ● Linux是c语言写成的 ● 符合POSIX标准 ● 作者是芬兰的Linus Torvalds ● 发展依赖于五个重要支柱: unix操作系统、minix操作系统、 GNU计划、POSIX标准和互联网 ● 2.6之后…

WebSocket:实现客户端与服务器实时通信的技术

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

CodeSys通过C函数接口调用Qt

文章目录 1.背景介绍2.修改makefile2.1.将编译器由c改成c2.2.使能opencv库2.3.使能Qt库 3.在代码中使用Qt库函数 1.背景介绍 建议先查看之前的文章【CodeSys中调用C语言写的动态库】&#xff0c;了解如何创建一个能够被codesys调用的动态库。 假如想要在函数中使用Qt或者第三方…

Vue3全家桶 - Vue3 - 【8】模板引用【ref】(访问模板引用 + v-for中的模板引用 + 组件上的ref)

模板引用【ref】 Vue3官网-模板引用&#xff1b;如果我们需要直接访问组件中的底层DOM元素&#xff0c;可使用vue提供特殊的ref属性来访问&#xff1b; 一、 访问模板引用 在视图元素上采用ref属性来设置需要访问的DOM元素&#xff1a; 该 ref 属性可采用 字符串 值的执行设…

【基于langchain + streamlit 完整的与文档对话RAG】

本地部署文档问答webdemo 支持 pdf支持 txt支持 doc/docx支持 源文档索引 你的点赞和收藏是我持续分享优质内容的动力哦~ 废话不多说直接看效果 准备 首先创建一个新环境&#xff08;选择性&#xff09; conda create -n chatwithdocs python3.11 conda activate chatwith…

Promise其实也不难

难点图解&#xff1a;then&#xff08;&#xff09;方法 ES6学习网站&#xff1a;ES6 入门教程 解决&#xff1a;回调地狱&#xff08;回调函数中嵌套回调&#xff09; 两个特点&#xff1a; &#xff08;1&#xff09;对象的状态不受外界影响。Promise对象代表一个异步操作&…

Linux常见指令总结

ls&#xff1a;显示当前目录下文件列表 常用的命令行参数&#xff1a; -l 显示更多的文件属性 -a 显示所有的文件/目录&#xff08;包括隐藏的&#xff09; -d 只显示目录 ps&#xff1a;参数可以叠加使用。 例如&#xff1a;ls -la 显示所有文件…

力扣刷题Days16(js)-67二进制求和

目录 1,题目 2&#xff0c;代码 2.1转换进制数 2.2模拟加法 3&#xff0c;学习与总结 Math.floor() 模拟加法思路回顾 重点复习巩固 模拟加法的思路和学习位运算&#xff1b; 今天没精力了&#xff0c;先休息 1,题目 给你两个二进制字符串 a 和 b &#xff0c;以二进制…

2m高分辨率土地利用分类矢量数据/植被类型分布数据

土地利用数据是在根据影像光谱特征&#xff0c;结合野外实测资料&#xff0c;同时参照有关地理图件&#xff0c;对地物的几何形状&#xff0c;颜色特征、纹理特征和空间分布情况进行分析&#xff0c;建立统一解译标志的基础之上&#xff0c;依据多源卫星遥感信息&#xff0c;结…

【Echarts】曲线图上方显示数字以及自定义值,标题和副标题居中,鼠标上显示信息以及自定义信息

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《前端》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

前端精准测试调用链路分析

精准测试在评估需求的测试范围时&#xff0c;需要评估一下代码的影响范围&#xff0c;这个范围有两部分&#xff1a;一是需求直接修改的代码&#xff1b;二是修改代码影响到的功能模块。代码影响到的功能一般是通过调用链路分析来实现的&#xff0c;java和kotlin代码可以由java…