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

写在前面

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

ps:点我跳转下集


文章目录

  • 写在前面
  • 一、命名空间域
    • 1.1、命名空间域的定义与使用
    • 1.2、命名空间域的细节
  • 二、 C++的输入/输出
    • 2.2、关于std命名空间的使用惯例
  • 三、缺省参数
  • 四、函数重载
    • 4.1、深入了解C++的重载机制
  • 五、C++98关键字


一、命名空间域

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

在这里插入图片描述
我们在全局中定义一个变量rand,但是rand函数在stdllib.h库中已经定义,根据我们学习过的程序的程序编译与链接笔记提到过,在连接中出现相同的变量符号表合并时会报错。
在这里插入图片描述
为了避免这种情况C++推出了新的关键字namespace,命名空间域。这样在全局中,我们就保护了我们自己定义的rand变量。在这里插入图片描述

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

定义命名空间,需要使用到 namespace关键字,后面跟命名空间的名字,然后接一对{} 即可,{}中即为命名空间的成员。
在这里插入图片描述

这时候我们运行程序,发现打印结果并不是我们自己创建的全局变量rand,如下图
在这里插入图片描述
这是因为被命名空间域保护起来的变量外界不能直接访问

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

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

但是需要注意的是,如果在上面代码中,我们直接使用rand会,程序会报错,如下图在这里插入图片描述
报出错误是rand不明确符号,不再是之前的重定义,所以我们使用using namespace命名空间名称引入,需要留意直接引入后的结果。


1.2、命名空间域的细节

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

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

命名空间域细节:

  1. 命名空间中可以定义变量/函数/自定义类型/类
namespace Bucai {int rand = 10;int k = 20;int Add(int left, int right){return left + right;}class MyName {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++将标准库的定义实现都放到这个命名空间中
using namespace std;//在平时练习中我们可以直接展开std命名空间域
int main()
{cout << "Hello world" << endl;return 0;
}

说明:

  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>
using namespace std;
int main()
{int a;double b;char c;// 可以自动识别变量的类型cin >> a;cin >> b >> c;cout << endl << a << endl;cout << b << "  " << c<< "  " << 12.888 << endl;return 0;
}

测试运行结果:
在这里插入图片描述


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

std是C++标准库的命名空间

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

三、缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

在这里插入图片描述

void Func(int a = 20)
{cout << a << endl;
}
int main()
{Func();		// 没有传参时,使用参数的默认值Func(10);	// 传参时,使用指定的实参return 0;
}

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

缺省参数类型:

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

传参时编译器读取实参是从左往右读取的,如果不是右往左指定缺省值,那么在实参传递时,会出现程序猿意想之外的错误,所以编译器会检查缺省值的给定,若出现缺省值的指定不是从右往左,则报错,如下图。
在这里插入图片描述
函数声明与定义分开的工程中,如果我们把缺省值放在定义中会出现报错:如下程序

//test.h
void Func(int a, int b, int c);//tect.c
#include "test.h"
void Func(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"
int main() {Func();return 0;
}

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


四、函数重载

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

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

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

在这里插入图片描述
我们设计一个交换函数,用来交换变量值:

void Swap(int* a, int* b) {  int num = *a;*a = *b;*b = num;
}
void Swap(double *a, double *b) {double num = *a;*a = *b;*b = num;
}int main() {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;return 0;
}

运行结果:
在这里插入图片描述
这样我们就完成了不同类型的变量交换,Swap函数形成了重载,这时C++编译器特有的属性

构成重载的三大要素:

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

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


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

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

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

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

我们在Linux环境下查看上面C语言生成的符号表(如下图)
在这里插入图片描述
在上图中,可以清晰看出在C语言中函数符号名有且只有一个,这样就导致了C语言的编译器不支持重载,而C++推出了全新玩法把编译后的函数符号名更改为另一种形式函数符号名,让其实现函数的重载

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

我们以上面代码为例:

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

我们在Linux环境下,查看由g++编译器编译后所形成的符号表查看函数符号名的变化,如下图。
在这里插入图片描述
此时C++中的函数,已经不再是单纯的Swap,而是在Swap前后增加了新东西。那一前一后的东西需要查看对应编译器的命名规则,如下。

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

  • 每个编译器都有自己的函数名修饰规则
  • g++编译器中的函数修饰后变成【_Z+函数长度+函数名+类型首字母
  • Windows下名字修饰规则在这里插入图片描述

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

  • _Z:固定开头
  • 4:代表着函数名字的长度,Swap长度4个字符,所以是4
  • Swap:代表了函数名
  • Pi:代表了int*类型的首字母合体,P代表是指针,i代表是整形。

在这里插入图片描述

void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}
void f(int a, double b, char c) {cout << "f(int a, double b, char c)" << endl;}
int main()
{f(10, 'a');f('a', 10);f(10, 2.5, 'a');return 0;
}

我们使用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:表情包来自网络,侵删🌹

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

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

相关文章

CGAL windows 安装教程

1.下载源代码 CGAL官网下载https://github.com/CGAL/cgal/releases 2.下载boost库 BOOST官网下载https://www.boost.org/ 3.下载 GMP and MPFR 4.配置VS2022 头文件&#xff1a; 库路径 做完以上步骤&#xff0c;可以使用CGAL了&#xff01;

从0入门自主空中机器人-2-2【无人机硬件选型-PX4篇】

1. 常用资料以及官方网站 无人机飞控PX4用户使用手册&#xff08;无人机基本设置、地面站使用教程、软硬件搭建等&#xff09;&#xff1a;https://docs.px4.io/main/en/ PX4固件开源地址&#xff1a;https://github.com/PX4/PX4-Autopilot 飞控硬件、数传模块、GPS、分电板等…

每天40分玩转Django:Django缓存

一、Django缓存概述 在高并发的Web应用中,缓存是提高性能的重要手段。通过缓存频繁访问的数据,可以显著减少数据库查询和渲染模板的时间,从而加快响应速度,提升用户体验。Django提供了多层级的缓存方案,可以灵活地满足不同场景下的缓存需求。 Django支持的缓存方式包括: 视图…

GraphRAG 框架哪家强?选择最适合你智能问答系统的框架

GraphRAG 框架哪家强&#xff1f;选择最适合你智能问答系统的框架 点击进入&#xff1a;GraphRAG系列文章-Nano-GraphRAG&#xff1a;打造轻量级医疗诊断助手 点击进入&#xff1a;GraphRAG系列文章-突破传统知识管理瓶颈&#xff1a;LlamaIndex GraphRAG 让企业知识问答更智能…

Mac电脑python多版本环境安装与切换

我当前是python3.9.6环境&#xff0c;需要使用3.9.8环境&#xff0c;通过brew安装3.9.8版本&#xff0c;然后通过pyenv切换环境 步骤 1: 安装 pyenv brew install pyenv brew install pyenv-virtualenv 步骤 2: 安装 Python 3.9.8&#xff08;使用 pyenv 安装指定版本的 Pyth…

Redis--持久化策略(AOF与RDB)

持久化策略&#xff08;AOF与RDB&#xff09; 持久化Redis如何实现数据不丢失&#xff1f;RDB 快照是如何实现的呢&#xff1f;执行时机RDB原理执行快照时&#xff0c;数据能被修改吗&#xff1f; AOF持久化是怎么实现的&#xff1f;AOF原理三种写回策略AOF重写机制 RDB和AOF合…

C高级:思维导图Day2

目录 总览1 总览2 总览1 压缩与解压缩 打包与解包 软连接与硬链接 ubuntu下关机与重启指令 总览2 结束

pwntools用法

pwntools 是一个Python库&#xff0c; 用于编写二进制漏洞利用&#xff08;exploitation&#xff09;脚本 功能&#xff1a; 远程连接和本地连接&#xff1a; 支持通过TCP/UDP连接远程服务或与本地进程进行交互。Shellcode和ROP链构造&#xff1a; 提供了便捷的工具来生成和利…

【每日学点鸿蒙知识】placement设置top、组件携带自定义参数、主动隐藏输入框、Web设置字体、对话框设置全屏宽

1、popup组件placement设置top没有生效&#xff1f; 可以用offset属性将popup往下边偏移一下 来规避 2、组件携带自定义参数的接口是哪个&#xff1f; 参考链接&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-attributes-…

PyTorch快速入门教程【小土堆】之优化器

视频地址优化器&#xff08;一&#xff09;_哔哩哔哩_bilibili import torch import torchvision from torch import nn from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential from torch.utils.data import DataLoaderdataset torchvision.datasets.CIFAR1…

数据库篇:mysql内置函数

前言 sql 是程序开发员绕不开的一项技能&#xff0c;而mysql是当前最流行的数据库&#xff0c;熟知其内置的一些函数&#xff0c;可以使我们平时的开发工作更加顺畅和方便 时间日期函数 字符串函数 数学计算相关函数 条件判断函数 加密和压缩函数 聚合函数 格式或类型转…

C# 中 Webclient和Httpclient

在C#中&#xff0c;WebClient和HttpClient&#xff0c;这两个类都是用于发起HTTP请求的客户端&#xff0c;它们在使用API上传文件或数据时有不同的优缺点和应用场景。在C#中WebClient是一种较早的网络客户端&#xff0c;而HttpClient是后期提供的更现代的、功能更强大的HTTP客户…

权限获得第一步

权限获得第一步 下载打开附件 给了一串加密的密文 一般都是用MD5加密&#xff0c;每一段分别解码一下 第一段不行&#xff0c;试一下第二段 这里发现第二段可以解码出来&#xff0c;这应该就是密码了 flag{3617656}

HTML 轮播图(Carousel)详细讲解

HTML 轮播图&#xff08;Carousel&#xff09;详细讲解 轮播图&#xff08;Carousel&#xff09;是一种常见的用户界面组件&#xff0c;用于在同一位置展示多个图像或内容&#xff0c;允许用户通过滑动或自动播放的方式查看不同的内容。它通常用于展示产品、图片、广告等。 1…

25秋招面试总结

秋招从八月底开始&#xff0c;陆陆续续面试了不少&#xff0c;现在也是已经尘埃落定&#xff0c;在这里做一些总结一些我个人的面试经历 腾讯 腾讯是我最早面试的一家&#xff0c;一开始捞我面试的是数字人民币&#xff0c;安全方向的岗位&#xff0c;属于腾讯金融科技这块。…

一份关于 Ubuntu 系统下代理配置的故障排查笔记

Ubuntu 网络代理配置与故障排查指南 在使用 Ubuntu 系统时&#xff0c;配置网络代理可以帮助提升网络访问速度或突破网络限制。然而&#xff0c;代理配置过程中可能会遇到各种问题。本文将详细介绍如何在 Ubuntu 下配置网络代理&#xff0c;并提供故障排查的步骤和解决方案。 …

001__VMware软件和ubuntu系统安装(镜像)

[ 基本难度系数 ]:★☆☆☆☆ 一、Vmware软件和Ubuntu系统说明&#xff1a; a、Vmware软件的说明&#xff1a; 官网&#xff1a; 历史版本&#xff1a; 如何下载&#xff1f; b、Ubuntu系统的说明&#xff1a; 4、linux系统的其他版本&#xff1a;红旗(redhat)、dibian、cent…

fiscoBcos中webase平台导出java项目

导出合约为java项目并调用 1&#xff0e; 在webase管理平台上面进行项目的导出 2.将下载好的项目解压并用idea打开&#xff0c;目录结构如下 在resources目录下的abi放的是编译过后的合约方法&#xff0c;bin.ecc放的是以编译过后的智能合约&#xff0c;conf文件夹下面放的是链…

【嵌入式C语言】指针数组结构体

指针与数组 指针与数组指针数组数组指针 多维数组数组名的保存 结构体定义结构体定义结构体变量使用typedef简化结构体声明访问结构体成员结构体内存分配字节对齐位域定义位域位域的限制示例 指针与数组 指针数组和数组指针是两个不同的概念&#xff0c;它们涉及到指针和数组的…

Junit4单元测试快速上手

文章目录 POM依赖引入业务层测试代码Web层测试代码生成测试类文件 在工作中我用的最多的单元测试框架是Junit4。通常在写DAO、Service、Web层代码的时候都会进行单元测试&#xff0c;方便后续编码&#xff0c;前端甩锅。 POM依赖引入 <dependency><groupId>org.spr…