【C++】初识C++之C语言加入光荣的进化(上)

【C++】初识C++之C语言加入光荣的进化(上)

写在前面

本篇笔记作为C++的开篇笔记,主要是讲解C++关键字(C++98)连带一点点(C++11)的知识。掌握的C++新语法新特性,当然C++是兼容C的,我们学习C的那套在C++中也是受用。

ps:点我跳转下集


文章目录


一、命名空间域

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


我们在全局中定义一个变量rand,但是rand函数在stdllib.h库中已经定义,根据我们学习过的程序的程序编译与链接笔记提到过,在连接中出现相同的变量符号表合并时会报错。

在这里插入图片描述


为了避免这种情况C++推出了新的关键字namespace,命名空间域。这样在全局中,我们就保护了我们自己定义的rand变量。

在这里插入图片描述

1.1、命名空间域的定义与使用

定义命名空间,需要使用到 namespace关键字,后面跟命名空间的名字,然后接一对{} 即可,{}中即为命名空间的成员。

在这里插入图片描述

这时候我们运行程序,发现打印结果并不是我们自己创建的全局变量rand,如下图

在这里插入图片描述


这是因为被命名空间域保护起来的变量外界不能直接访问

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

  • 加命名空间名称及作用域限定符( :: )
namespace Bucai {int rand =10;int k =20;}intmain(){printf("%d\n", Bucai::k);return0;}
  • 使用using将命名空间中某个成员引入
namespace Bucai {int rand =10;int k =20;}using Bucai::k;intmain(){printf("%d\n", k);return0;}
  • 使用using namespace 命名空间名称 引入
    这个效果是暴露命名空间域的内容,让外部可以直接访问。但是这和直接全局中定义变量的效果是不一样的,因为在命名空间域中有标识,在编译连接中形成的符号表不会与在全局变量中定义的吻合
#include<stdio.h>#include<stdlib.h>namespace Bucai {int rand =10;int k =20;}usingnamespace Bucai;intmain(){printf("%d\n", k);return0;}

但是需要注意的是,如果在上面代码中,我们直接使用rand会,程序会报错,如下图

在这里插入图片描述


报出错误是rand不明确符号,不再是之前的重定义,所以我们使用using namespace命名空间名称引入,需要留意直接引入后的结果。


1.2、命名空间域的细节

命名空间域也是域,它与作用域的细节是相似的,代码块就是作用域的一种表现形式,我们使用代码块理解命名空间域会更好,在代码块中,我们定义的变量等与外界是互不干涉的,而且在代码块中我们使用对应的变量采用的是就近原则,而且在代码块中可以嵌套代码块,在代码块外面访问不了代码块的内容,因为在代码块中的内容出了代码块作用域就结束。

命名空间域我们可以理解为一个有名称的代码块。必须定义在全局中的"代码块",在域中可以随意的定义变量,这样外界不会与域中变量命有冲突,当我们想要使用域中变量时,可以通过域名+作用域限定符来完成引用

命名空间域细节:

  1. 命名空间中可以定义变量/函数/自定义类型/类
namespace Bucai {int rand =10;int k =20;intAdd(int left,int right){return left + right;}classMyName{public:int age =18;};}
  1. 命名空间可以嵌套
namespace Bucai {int k =0; namespace bbbb {int age =18;}}
  1. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。

二、 C++的输入/输出

C++兼容C,自然是支持C的标准输入输出的,但是C的标准输入输出有点麻烦,每次都需要程序猿手动标识这个变量是上面类型,需要使用%什么来进行输出,很麻烦,所以C++推出了一个全新玩法。

#include<iostream>// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中usingnamespace std;//在平时练习中我们可以直接展开std命名空间域intmain(){ cout <<"Hello world"<< endl;return0;}

说明:

  1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含<iostream>头文件以及按命名空间使用方法使用 std
  2. coutcin是全局的流对象endl是特殊的C++符号,表示换行输出(即C中的\n),他们都包含在包含<iostream>头文件中。
  3. <<是流插入运算符,>>是流提取运算符
  4. 使用C++输入输出更方便不需要printf/scanf输入输出时那样,需要手动控制格式C++输入输出可以自动识别变量类型
  5. 实际上coutcin分别是ostreamistream类型的对象,>><<也涉及运算符重载等知识。后面不才专门写一篇笔记来讲解IO流用法及原理。
  6. C++中为了兼容C语言,在C++ 使用流输入输出时需要检查C语言的输入输出,从原理的角度说,C++ 的输入输出效率是比C语言的输入输出要低的

注意: 早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用<iostream>+std的方式来使用。

在这里插入图片描述
#include<iostream>usingnamespace std;intmain(){int a;double b;char c;// 可以自动识别变量的类型 cin >> a; cin >> b >> c; cout << endl << a << endl; cout << b <<" "<< c<<" "<<12.888<< endl;return0;}

测试运行结果:

在这里插入图片描述

2.2、关于std命名空间的使用惯例

std是C++标准库的命名空间
  1. 日常练习中,建议直接using namespace std即可,这样就很方便。
  2. 项目开发中,using namespace std展开,标准库就全部暴露出来了,但是项目开发中代码较多、规模大,就很容易出现冲突问题。所以建议在项目开发中使用,像std::cout这样使用是 指定命名空间 + using std::cout展开常用的库对象/类型等方式

三、缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
在这里插入图片描述
voidFunc(int a =20){ cout << a << endl;}intmain(){Func();// 没有传参时,使用参数的默认值Func(10);// 传参时,使用指定的实参return0;}

测试运行结果:

在这里插入图片描述


在上结果图中,我们也可以看出在函数定义中,我们设计了一个形参,但是形参给了一个缺省值20,在我们调用函数时,我们没有给形参a传递实参时,a就使用缺省值,所以打印20,在我们有传递实参时,形参就接收实参参数,缺省值就失效了,所以打印10

缺省参数类型:

  • 全缺省参数
voidFunc(int a =10,int b =20,int c =30){ cout <<"a = "<< a << endl; cout <<"b = "<< b << endl; cout <<"c = "<< c << endl;}
  • 半缺省参数
    • 半缺省参数必须从右往左依次来给出,不能间隔着给
    • 缺省参数不能函数声明和定义同时出现,如果函数声明和定义分开,缺省参数需要在声明中指定
    • 缺省值必须是常量或者全局变量
    • C语言不支持(编译器不支持)
voidFunc(int a,int b =10,int c =20)//从右往左依次指定缺省值{ cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl;}

传参时编译器读取实参是从左往右读取的,如果不是右往左指定缺省值,那么在实参传递时,会出现程序猿意想之外的错误,所以编译器会检查缺省值的给定,若出现缺省值的指定不是从右往左,则报错,如下图。

在这里插入图片描述


函数声明与定义分开的工程中,如果我们把缺省值放在定义中会出现报错:如下程序

//test.hvoidFunc(int a,int b,int c);//tect.c#include"test.h"voidFunc(int a =10,int b =20,int c =30){ cout <<"a = "<< a << endl; cout <<"b = "<< b << endl; cout <<"c = "<< c << endl;}//main.c#include"test.h"intmain(){Func();return0;}

测试结果:

在这里插入图片描述


程序编译与链接笔记中,我们已经知道#include引用的头文件,最后都是拷贝头文件内容到当前文件下的。
test.h头文件中,我们只声明了没有缺省值的Func函数,在编译阶段拷贝到工程中,就不是有缺省值的函数,所以报错。


四、函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。
比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”。

谁也赢不了虽然是一样的字,但是意思完全不一样,这就形成了重载,同理,C++中也做出了相似的函数重载。

函数重载: 是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数要求这些同名函数形参列表 (参数个数类型类型顺序) 不同,常用来处理实现功能类似数据类型不同的问题。
在这里插入图片描述


我们设计一个交换函数,用来交换变量值:

voidSwap(int* a,int* b){int num =*a;*a =*b;*b = num;}voidSwap(double*a,double*b){double num =*a;*a =*b;*b = num;}intmain(){int a =10, b =20;Swap(&a,&b); cout <<"a = "<< a <<" b = "<< b << endl;double c =10.12, d =20.12;Swap(&c,&d); cout <<"c = "<< c <<" d = "<< d << endl;return0;}

运行结果:

在这里插入图片描述


这样我们就完成了不同类型的变量交换,Swap函数形成了重载,这时C++编译器特有的属性

构成重载的三大要素:

  1. 形参个数不同
  2. 形参类型顺序不同
  3. 形参类型不同

注意:函数的返回值不同是不构成函数重载的!!


4.1、深入了解C++的重载机制

在深入了解之前,我们先认识一下C语言为什么不支持重载,但在此之前我们需要清楚C/C++的程序编译与链接,因为重载机制核心是发生在编译阶段完成的。

在C语言中,我们根据不才写的程序编译与链接笔记可以知道,在程序在经过编译后我们的函数符号名是不会有改变的。我们以下程序为例:

#include<stdio.h>voidSwap(int* a,int* b){int num =*a;*a =*b;*b = num;}intmain(){int a =10;int b =20;Swap(&a,&b);printf("%d \n",a);return0;}

我们在Linux环境下查看上面C语言生成的符号表(如下图)

在这里插入图片描述


在上图中,可以清晰看出在C语言中函数符号名有且只有一个,这样就导致了C语言的编译器不支持重载,而C++则推出了全新玩法把编译后的函数符号名更改为另一种形式函数符号名,让其实现函数的重载

在Windows环境下,函数命名太过复杂,不才这里使用 g++编译器

我们以上面代码为例:

#include<stdio.h>voidSwap(int* a,int* b){int num =*a;*a =*b;*b = num;}intmain(){int a =10;int b =20;Swap(&a,&b);printf("%d \n",a);return0;}

我们在Linux环境下,查看由g++编译器编译后所形成的符号表查看函数符号名的变化,如下图。

在这里插入图片描述


此时C++中的函数,已经不再是单纯的Swap,而是在Swap前后增加了新东西。那一前一后的东西需要查看对应编译器的命名规则,如下。

C++的函数符号名命名规则:

  • 每个编译器都有自己的函数名修饰规则
  • g++编译器中的函数修饰后变成【_Z+函数长度+函数名+类型首字母

Windows下名字修饰规则

在这里插入图片描述

根据命名规则我们可以得出交换函数Swap在C++形成_Z4SwapPiS_代表着:

  • _Z:固定开头
  • 4:代表着函数名字的长度,Swap长度4个字符,所以是4
  • Swap:代表了函数名
  • Pi:代表了int*类型的首字母合体,P代表是指针,i代表是整形。
在这里插入图片描述
voidf(int a,char b){ cout <<"f(int a,char b)"<< endl;}voidf(char b,int a){ cout <<"f(char b, int a)"<< endl;}voidf(int a,double b,char c){ cout <<"f(int a, double b, char c)"<< endl;}intmain(){f(10,'a');f('a',10);f(10,2.5,'a');return0;}

我们使用g++编译器,生成符号表查看上面函数f的符号名,如下图

在这里插入图片描述


第一个函数f:后面的类型是ic,对应形参中的intchar
第二个函数f:后面的类型是ci,对应形参中的charint
第三个函数f:后面的类型是idc,对应形参中的intdoublechar

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

有此,我们可以总结出,函数的重载只会与形参列表 中的 参数个数类型类型顺序相关,因为只有这些才控制着函数符号名。当函数的符号名相同时,编译器在链接时候也是会区分不开,所以必须保证函数符号名唯一


五、C++98关键字

C++总计63个关键字(其中包含C语言32个关键字),如下表格

asmdoifreturntrycontinue
autodoubleinlineshorttypedeffor
booldynamic_castintsignedtypeidpublic
breakelselongsizeoftypenamethrow
caseenummutablestaticunionwchar_t
catchexplicitnamespacestatic_castunsigneddefault
charexportnewstructusingfriend
classexternoperatorswitchvirtualregister
constfalseprivatetemplatevoidtrue
const_castfloatprotectedthisvolatilewhile
deletegotoreinterpret_cast

ps:点我跳转下集

以上就是本章所有内容。若有勘误请私信不才。万分感激💖💖 如果对大家有用的话,就请多多为我点赞收藏吧~~~💖💖

请添加图片描述

ps:表情包来自网络,侵删🌹

Read more

Python 基础语法练习题

1. 变量与数据类型 定义一个整数、一个浮点数、一个字符串和一个布尔值,然后分别打印它们的值和类型。 2. 字符串操作 输入一个句子,统计其中单词的数量,并将每个单词的首字母大写后输出。 3. 列表操作 创建一个包含 1~10 的列表,删除所有偶数,然后将剩余元素乘以 2 后打印。 4. 字典操作 创建一个存储学生姓名和成绩的字典(至少 5 名学生),找出成绩最高和最低的学生并打印。 5. 条件判断 输入一个年份,判断是否为闰年(能被 4 整除但不能被 100 整除,或能被 400 整除)。 6. 循环 用 while 循环实现猜数字游戏:程序随机生成 1~100 的整数,用户不断猜测,

【Python 爬虫实战】抓取 BOSS 直聘

一、前言 在求职或行业调研过程中,我们常常需要批量获取招聘平台的岗位信息,手动复制粘贴效率极低。本文将通过 DrissionPage 框架实现BOSS 直聘大数据开发岗位的批量爬取,无需分析复杂的页面元素,直接监听接口数据包获取 JSON 数据,最终将结果存入 CSV 文件,全程代码简洁易懂,新手也能快速上手。 本次实战目标 1. 监听 BOSS 直聘岗位列表接口,获取结构化 JSON 数据 2. 提取岗位名称、公司、薪资、学历要求等核心信息 3. 将爬取结果批量存入 CSV 文件,方便后续数据分析 4. 实现自动翻页,爬取前 20 页的岗位数据 二、环境准备 1. 所需 Python 库 本次实战核心使用 DrissionPage 框架(

Python通往AI之路:从基础编程到智能应用的全面指南

Python通往AI之路:从基础编程到智能应用的全面指南

Python通往AI之路:从基础编程到智能应用的全面指南 在当今的技术浪潮中,Python无疑已成为人工智能(AI)领域最受欢迎的编程语言。其简洁的语法、丰富的库生态以及强大的社区支持,使得从初学者到资深研究者,都能利用Python轻松踏入AI的世界。本文将带你探索如何从Python基础出发,逐步掌握AI核心技能,并展望这一技术融合所带来的无限可能。 一、筑基:掌握Python,开启AI大门 任何宏伟的建筑都始于坚实的地基。在涉足复杂的AI算法之前,牢固掌握Python编程基础是至关重要的一步。 * 核心语法与数据结构:你需要熟悉Python的基础语法、缩进规则、关键字以及编码规范。同时,深入理解变量、多种数据类型(如列表、字典、元组)以及流程控制(条件语句、循环)是进行数据处理的前提。 * 进阶编程技术:随着学习的深入,你会接触到函数与模块化编程、文件读写操作以及面向对象编程等高级概念。这些技术能帮助你构建更复杂、更易于维护的AI项目。 * 开发环境搭建:选择一个顺手的开发工具至关重要。PyCharm、Jupyter Notebook或Google Colab都是AI

【3月考】二级Python最新真题及满分代码合集(简单应用题部分)

【3月考】二级Python最新真题及满分代码合集(简单应用题部分)

本套试题内容适配2026年3月考试 文本结尾提供所有题目配套电子版及素材和答案 祝大家优秀拿下!!! 第1套题 【题目素材】 # 以下代码为提示框架# 请在...处使用一行或多行代码替换# 请在______处使用一行代码替换## 注意:提示框架代码可以任意修改,以完成程序功能为准 txt =input("请输入类型序列: ")... d ={}... ls =list(d.items()) ls.sort(key=lambda x:x[1], reverse=True)# 按照数量排序for k in ls:print("{}:{}".format(k[0], k[1])) 【参考代码】 # 以下代码为提示框架# 请在...处使用一行或多行代码替换# 请在______处使用一行代码替换#