【C++入门基础(上)】

news2024/11/17 19:29:51

Cross the stars over the moon to meet your better-self.

 

 

目录

1 命名空间

 1.1 命名空间定义

1.2 命名空间使用

1.2.1 加命名空间名称及作用域限定符

 1.2.2 使用using将命名空间中成员引入

 1.2.3 使用using namespace 命名空间名称引入

2 C++输入&&输出

3 缺省参数

3.1 全缺省参数

3.2 半缺省参数

4. 函数重载

 4.1 函数重载概念

4.2 名字修饰(name Mangling)

 5 总结


1 命名空间

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

 1.1 命名空间定义

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

我们可以来举一些例子:

#include<stdio.h>
#include<stdlib.h>

int rand = 1;
int main()
{
	
	printf("%d\n", rand);
	return 0;
}

为啥这段代码会报错呢?

 经过分析我们不难发现我们自己定义的rand与官方库里定义的rand函数冲突了,解决方法就是用命名空间来隔离我们所定义的变量或者函数:

namespace grm
{
	int rand = 1;
}

我们发现这样就可以编译通过了。

注意:

1 命名空间中的内容,既可以定义变量,也可以定义函数;

2 命名空间可以嵌套 ;

3 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。

像下面这两种方式都是合理的:


// 命名空间可以嵌套
namespace grm
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}

	namespace N3
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}

而且最后编译器会将同一个工程中相同的命名空间合并为一个命名空间。但是值得注意的是一旦命名空间中变量定义了就不可以在命名空间中修改:

 这样都会导致编译器报错的。

一个命名空间就定义了一个新的作用域 ,命名空间中的所有内容都局限于该命名空间中。这句话的意思简单点来说就是我们自己定义的命名空间就是一个隔离区,不会与库里面的变量或者函数发生冲突,那么应该如何使用命名空间呢?

1.2 命名空间使用

1.2.1 加命名空间名称及作用域限定符

什么是作用域限定符呀?

::   (两个冒号)

namespace grm
{
	int rand = 1;
	int ret = 1001;

	int Add(int x, int y)
	{
		return x + y;
	}
}


int main()
{
	
	printf("%d\n", grm::rand);
	printf("%d\n", grm::ret);
	printf("%d\n", grm::Add(10,20));

	return 0;
}

 1.2.2 使用using将命名空间中成员引入

#include<stdio.h>
//#include<stdlib.h>

namespace grm
{
	int rand = 1;
	int ret = 1001;

	int Add(int x, int y)
	{
		return x + y;
	}
}

using grm::rand;
using grm::Add;
int main()
{
	
	printf("%d\n", rand);
	printf("%d\n", grm::ret);
	printf("%d\n", Add(10,20));

	return 0;
}

这个时候记得把库里面的rand给屏蔽了,不然就会冲突。

 1.2.3 使用using namespace 命名空间名称引入

这种方式最为简单,但是不推荐在工程里面用,否则可能会发生命名冲突的问题,平常的代码练习可以这样做(因为代码量不会太大,一般不会冲突)

using namespace grm;
int main()
{
	
	printf("%d\n", rand);
	printf("%d\n", ret);
	printf("%d\n", Add(10,20));

	return 0;
}

2 C++输入&&输出

#include<iostream>

int main()
{
	int i;
	char c;
	double d;
	std::cin >> i >> c >> d;
	std::cout << i << " " << c << " " << d << std::endl;
	return 0;
}

说明:

1. 使用 cout 标准输出 ( 控制台 ) cin 标准输入 ( 键盘 ) 时,必须 包含 < iostream > 头文件 以及 std 标准命名空间。
注意:早期标准库将所有功能在全局域中实现,声明在 .h 后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在 std 命名空间下,为了和 C 头文件区分,也为了正确使用命名空间,规定 C++ 头文 件不带 .h ;旧编译器 (vc 6.0) 中还支持 <iostream.h> 格式,后续编译器已不支持,因此 推荐 使用 <iostream>+std 的方式。
2. 使用 C++ 输入输出更方便,不需增加数据格式控制,比如:整形 --%d ,字符 --%c
3 其中<< 表示流插入符   >>表示流提取符
4 endl表示换行。

 但是上面老是用std::很麻烦,平常练习中我们为了轻松一点儿可以直接用

using namespace std 直接将库中所有的函数和变量都引出来,但是在工程中并不推荐这样做。

#include<iostream>
using namespace std;
int main()
{
	int i;
	char c;
	double d;
	cin >> i >> c >> d;
	cout << i << " " << c << " " << d << endl;
	return 0;
}

我们发现了用cin && cout居然不用管变量的类型是啥,不像C语言还得记住整形用%d 字符用%c 等等。但是万事也不是绝对,有时用scanf && printf比用cin && cout要简单些,具体情况具体分析,一般来说,哪种方便用哪个,甚至还可以组合使用。


3 缺省参数

大家知道什么是备胎吗?

 缺省参数差不多就是充当备胎这么一个角色

而缺省型参数又分为全缺省参数和半缺省参数。

3.1 全缺省参数

#include<iostream>
using namespace std;

int Add(int x = 10, int y = 20, int z = 30)
{
	return x + y + z;
}
int main()
{
	cout << Add(1, 2, 3) << endl;
	cout << Add(1, 2) << endl;
	cout << Add(1) << endl;
	cout << Add( ) << endl;

	return 0;
}

输出结果:

 我们发现参数的接受是从左到右的。

3.2 半缺省参数

void Func(int a, int b = 10, int c = 20)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;
}

int main()
{
	Func(1);
	Func(1, 2);
	Func(1, 2, 3);
	return 0;
}
注意:
1. 半缺省参数必须从右往左依次来给出,不能间隔着给
这种方式是错误的:

 2. 缺省参数不能在函数声明和定义中同时出现

我们重新定义一个Func.h的头文件,将Func的声明放进去,然后编译:

 我们只需要将缺省参数放在其中一个就行了,一般是定义在声明中。

 3. 缺省值必须是常量或者全局变量

4. C语言不支持(编译器不支持)


4. 函数重载

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

 4.1 函数重载概念

函数重载 : 是函数的一种特殊情况, C++ 允许在 同一作用域中 声明几个功能类似 的同名函数 ,这些同名函数的形参列表 ( 参数 个数 类型 顺序 ) 必须不同 ,常用来处理实现功能类似数据类型不同的问题.
int Add(int left, int right)
{
	return left + right;
}

int Add(int left, char right)
{
	return left + right;
}

int Add(char right, int left)
{
	return left + right;
}

int Add(char right, int left, int mid)
{
	return left + right + mid;
}


int main()
{
	cout << Add(1, 2) << endl;
	cout << Add(1, 'a') << endl;
	cout << Add('a', 1) << endl;
	cout << Add(1, 'a', 2) << endl;

	return 0;
}

 上面这些都构成函数重载:

 但是这种呢?

int Add(int left, int right)
{
	return left + right;
}

char Add(int left, int right)
{
	return left + right;
}
int main()
{
	Add(1, 3);
	return 0;
}

 很明显,此时编译器就报了错误。注意:返回值不同不能构成重载。因为函数调用时你不知道到底要调用哪一个。

这种能构成重载吗?

void f()
{
	cout << "f( )" << endl;
}

void f(int x = 0)
{
	cout << "f( x=0 )" << endl;
}

我们编译一下代码发现能够跑过,说明这是构成重载的,但是如果你调用该函数带上参数还好,如果不带参数那编译器就不知道要调用哪个函数了,这是就会报错。

4.2 名字修饰(name Mangling)

为什么C++支持函数重载,而C语言不支持函数重载呢?

C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接

有关具体的详解可以参考我的这篇博客程序环境和预处理

1. 实际我们的项目通常是由多个头文件和多个源文件构成,而通过我们 C 语言阶段学习的编译链接,我们可以知道,【当前 a.cpp 中调用了 b.cpp 中定义的 Add 函数时】,编译后链接前, a.o 的目标文件中没有 Add 的函数地址,因为 Add 是在 b.cpp 中定义的,所以 Add 的地址在 b.o 中。那么怎么办呢?
2. 所以链接阶段就是专门处理这种问题, 链接器看到 a.o 调用 Add ,但是没有 Add 的地址,就会到 b.o 的符号表中找 Add 的地址,然后链接到一起
3. 那么链接时,面对 Add 函数,链接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。
4. 由于 Windows vs 的修饰规则过于复杂,而 Linux gcc 的修饰规则简单易懂,下面我们使用了 gcc 演示了这个修饰后的名字。
5. 通过下面我们可以看出 gcc 的函数修饰后名字不变。而 g++ 的函数修饰后变成【 _Z+ 函数长度 + 函数名 + 类型首字母】。
采用 C 语言编译器编译后结果 :
结论: linux 下,采用 gcc 编译完成后,函数名字的修饰没有发生改变。
采用 C++ 编译器编译后结果 :
结论: linux 下,采用 g++ 编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息
添加到修改后的名字中。
Windows 下名字修饰规则 :

 对比Linux会发现,windowsC++编译器对函数名字修饰非常诡异,但道理都是一样的。

【扩展学习:C/C++函数调用约定和名字修饰规则】

C++函数重载

C++调用约定
这里大家有兴趣了解下就好。
6. 通过这里就理解了 C 语言没办法支持重载,因为同名函数没办法区分。而 C++ 是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
7. 另外我们也理解了,为什么函数重载要求参数不同!而跟返回值没关系。
面试题:
1. 下面两个函数能形成函数重载吗?有问题吗或者什么情况下会出问题?
void TestFunc(int a = 10)
{
 cout<<"void TestFunc(int)"<<endl;
}
void TestFunc(int a)
{
 cout<<"void TestFunc(int)"<<endl;
}

回答:很明显这两个函数是无法构成函数重载的,因为参数个数类型顺序是相同的,传了参数后也无法识别调用哪一个函数。

2. C 语言中为什么不能支持函数重载?
回答:因为编译的时候两个重载函数的函数名相同,符号表中会存在歧义和冲突,其次在链接时也会有冲突,因为他们都是直接用函数名去标识和查找。

 3. C++中函数重载底层是怎么处理的?

回答:因为C++不是直接用函数名去标识和查找函数的,而是用函数名修饰规则,只要参数的个数,类型,顺序不同,符号表的函数就不会存在歧义和冲突了,链接时去调用两个重载函数查找地址时也是明确的。


 5 总结

本文介绍了命名空间的定义和使用,C++输入输出的使用,缺省参数以及函数重载,重点讲解了函数重载是怎样实现的以及C语言不支持函数重载C++支持函数重载的原因。引用将放在下一篇博客来讲。

如果该文对你有用,能不能一键3连支持一下播主呢

 

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

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

相关文章

Mentor-dft 学习笔记 day47-On-Chip Clock Controller Design Description

On-Chip Clock Controller Design Description有三种类型的片上控制器设计&#xff1a;standard, parent, and child。可以根据设计要求选择它们。使用OCC时&#xff0c;必须考虑本节中讨论的设计元素。The Standard OCC 标准OCC为快速捕获提供快速时钟&#xff0c;为换档和慢速…

Java字节流的使用:字节输入/输出流、文件输入/输出流、字节数组输入/输出流

InputStream 是 Java 所有字节输入流类的父类&#xff0c;OutputStream 是 Java 所有字节输出流类的父类&#xff0c;它们都是一个抽象类&#xff0c;因此继承它们的子类要重新定义父类中的抽象方法。 这里首先介绍上述两个父类提供的常用方法&#xff0c;然后介绍如何使用它们…

springboot整合shiro + jwt + redis实现权限认证(上手即用)

目录前言项目结构依赖导入建数据库表建表语句使用插件生成增删改查添加MyRealm添加ShiroConfig添加JwtFilterJWT相关得类JwtTokenJwtAudienceJwtHelper添加BeanFactory只贴出主要得类&#xff0c;具体得可以看我的gitee&#xff0c;接口都自测过的。前言 最近项目中涉及到使用…

NEST.JS使用心得

最近部门分享了nest.js技术&#xff0c;旨在前端人员通过项目积累将可重复使用的数据或者自己需要的数据通过nest设计出接口方便快速开发&#xff0c;不需要等待后端开发人员的数据。学习了两天发现nest很有意思&#xff0c;所以来分享下最近两天的学习心得。 nest中文文档&am…

linux下使用命令TC进行网络限流 —— 筑梦之路

Linux 下的流量控制原理 通过对包的排队&#xff0c;我们可以控制数据包的发送方式。这种控制&#xff0c;称之为数据整形&#xff0c;shape the data&#xff0c;包括对数据的以下操作: 增加延时 丢包 重新排列 重复、损坏 速率控制 在 qdisc-class-filter 结构下&#x…

ADI Blackfin DSP处理器-BF533的开发详解64:电子相册的设计(含源码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 代码实现功能 代码实现了将 SD 卡根目录下的所有文件进行文件列表&#xff0c;然后将 480*272 尺寸的 JPEG 文件进行 JPEG 解码&#xff0c;将解…

校园跳蚤市场平台/校园二手交易系统

摘 要 本文论述了校园跳蚤市场平台的设计和实现&#xff0c;该网站从实际运用的角度出发&#xff0c;运用了计算机网站设计、数据库等相关知识&#xff0c;网络和Mysql数据库设计来实现的&#xff0c;网站主要包括学生注册、学生登录、浏览商品、搜索商品、查看商品并进行购买…

Blender——“苹果”建模

效果图 1.调出点线面面板&#xff0c;衰减编辑 1.1打开blender&#xff0c;点击常规&#xff0c;按A全选物体&#xff08;摄像头、光源、正方体&#xff09;&#xff0c;按delete删除。 1.2 在3D视图中添加一个经纬球。点击添加&#xff0c;选择网格—>经纬球。 1.3 点击下…

前端JS也可以连点成线(Vue中运用 AntVG6)

前言 什么是 G6&#xff1f;G6 是一个图可视化引擎。它提供了图的绘制、布局、分析、交互、动画等图可视化的基础能力。旨在让关系变得透明&#xff0c;简单。让用户获得关系数据的 Insight。其实说白了就是我们前端中的绘图工具&#xff1b;基于 G6&#xff0c;用户可以快速搭…

Linux基础知识-文件目录结构及基本属性

1、前言 上一篇我们讲到了Linux 文件类型7种类型&#xff0c;本篇我们说说Linux文件目录结构。 2、Linux 目录树 所有可操作的计算机资源都存在于目录树这个结构中&#xff0c;对计算资源的访问&#xff0c;可以看做是对这棵目录树的访问。Linux 的目录结构如下&#xff1a;…

常见日志框架使用及日志打印规范设计

文章目录一、slf4j 简介二、常用日志框架1&#xff09;log4jpom 依赖log4j.properties 文件配置测试参考2&#xff09;logbackpom 依赖logback.xml 配置测试参考3&#xff09; java.util.logging4&#xff09;commons loggingpom 依赖配置测试参考5&#xff09;slf4j-simplepom…

MFC UI控件相关

文章目录UI控件相关CDialog::OnInitDialog() 对话框初始化手动添加UpdateData() 刷新窗口数据DoDataExchange()数据与控件动态绑定afx_msg: 声明一个消息响应函数void AFXAPI DDX_Control( CDataExchange* pDX, int nIDC, CWnd& rControl );DDV_MaxChars()UI控件相关 CDia…

20天学会Rust第一天之Helloword

阿sir今天开始学习Rust了&#xff0c;至于为什么学习呢&#xff1f; 以后再说 我们都知道&#xff0c;程序设计 数据结构 算法。 因此&#xff0c;我们依次学习Rust中数据结构的定义&算法的实现&#xff0c;然后用它们实现一个简单的“hello world” 数据结构 Rust提供…

什么是IoC和AOP

IoC是什么&#xff1f; 控制反转&#xff1a;面向对象的设计的理念。上层建筑依赖下层建筑 理解&#xff1a;行李箱设计 轮子 --> 底盘 --> 箱体 --> 行李箱 如果改动轮子&#xff0c;则底盘、箱体、行李箱都需要进行调整。 依赖注入&#xff1a;将底层类作为参数…

Spring之底层架构核心概念-BeanFactory 与ApplicationContext

目录1.BeanFactory2.ApplicationContext3.关系4.总结1.BeanFactory BeanFactory是一个接口 public interface BeanFactory {xxx... }2.ApplicationContext ApplicationContext 也是一个接口&#xff0c;继承自ListableBeanFactory, HierarchicalBeanFactory public interfa…

非零基础自学Golang 第15章 Go命令行工具 15.2 代码获取(get) 15.3 格式化代码(fmt)

非零基础自学Golang 文章目录非零基础自学Golang第15章 Go命令行工具15.2 代码获取(get)15.3 格式化代码(fmt)第15章 Go命令行工具 15.2 代码获取(get) go get命令用于从远程仓库中下载安装远程代码包&#xff0c;这是我们常用且非常重要的指令。 我们在开发程序时往往需要引…

Gateway网关-网关作用介绍

为什么需要网关&#xff1f; 如果允许任何人访问微服务&#xff0c;查看我们的敏感业务&#xff0c;这样数据是不是不安全。如果是我们的工作人员并且有相应的查看权限&#xff0c;我们才提供访问权限。那谁来做这件事呢&#xff1f;就是我们的网关。 网关的功能作用 1&#xf…

鼎镁科技冲刺上交所:年营收18亿 拟募资13亿

雷递网 雷建平 12月21日鼎镁新材料科技股份有限公司&#xff08;简称&#xff1a;“鼎镁科技”&#xff09;日前递交招股书&#xff0c;准备在上交所主板上市。鼎镁科技计划募资12.86亿元。其中&#xff0c;8.84亿元用于轻量化新材料生产、研发建设项目&#xff0c;2.53亿元用于…

消息号F5155处理办法

消息号F5155&#xff08;没有公司代码XDJT中买卖双方的资金权限&#xff09;处理办法 OBA4先检查用户的FI容差组 OB57查看分配用户给容差组&#xff0c;确认是否书写正确的容差组。