【C++】C++入门1.0

鼠鼠最近在学C++,那么好,俺来做笔记了!

目录

1.C++关键字(C++98)

2.命名空间

2.1.命名空间定义

2.2.命名空间的使用 

 3.C++的输入&&输出

4.缺省参数

4.1缺省参数概念

4.2.缺省参数的分类

5.函数重载

5.1.函数重载概念

 5.2.C++支持函数重载的原理--名字修饰(name Mangling)


C++是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式 等。本博客介绍的知识点主要是补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的,比如:作用 域方面、IO方面、函数方面、指针方面、宏方面等。 

1.C++关键字(C++98)

C++总计63个关键字,C语言32个关键字。

本图片是本鼠借鉴别人的劳动成果(其实本鼠的博客很多都是捏)!

本鼠是初学者,肯定介绍不出这些个关键字的所以然来,以后本鼠学习到的话会在后面的博客介绍的捏!

2.命名空间

我们知道在C语言中,在同一个域里面不能有重复的函数名,变量名。例如C语言:

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
int main()
{
	printf("%d\n", rand);
	return 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”

头文件<stdlib.h>中定义过rand是“函数”,并且“函数”rand定义在全局域当中,我们又定义了全局变量rand,导致rand重定义!

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

2.1.命名空间定义

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

注意:以下代码如果写在.c文件中会报错!


1.正常的命名空间定义。

// HD是命名空间的名字,一般开发中是用项目名字做命名空间名
namespace HD
{
	// 命名空间的成员可以定义变量/函数/类型
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct LCD
	{
		int age;
		double weight;
		struct LCD* next;
	};
}

2. 命名空间可以嵌套。

namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}

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

例如本鼠有一个工程,工程包含test.cpp和test.h。

在test.cpp中定义了:

namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}

在test.h中定义了:

namespace HD
{
	typedef struct SListNode
	{
		int data;    
		struct SListNode* next;  
	}SListNode;
	char a[] = {'w','x','h','l','c','d'};
}

那么好,神奇的事发生了,一个工程中的test.h和test.cpp中两个HD会被合并成一个 。

 再例如本鼠有一个工程,工程包含只test.cpp文件。

在test.cpp中定义了:

namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}

namespace HD
{
	typedef struct SListNode
	{
		int data;    
		struct SListNode* next;  
	}SListNode;
	char a[] = {'w','x','h','l','c','d'};
}

那么好,一个上面的两个HD也会被合并成一个 。


 注意:

1.一个命名空间就定义了一个新的作用域(命名空间域使用using将命名空间中某个成员引入),命名空间中的所有内容都局限于该命名空间中。

2.局部域和全局域会影响生命周期和访问,而命名空间域只影响访问。如何影响访问?请看下面本鼠介绍的编译器的访问规则。

3.命名空间封装的成员生命周期与全局变量的生命周期是一样的,命名空间定义的变量都是全局变量,所以说命名空间域不影响生命周期。

2.2.命名空间的使用 

如何使用命名空间的成员,例如:

#include<stdio.h>
namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}

int main()
{
	//编译报错:error C2065: “rand”: 未声明的标识符
	printf("%d", rand);
	return 0;
}

这里为什么报错?

 不得不提编译器的访问规则:

1.如果没有指定域。优先访问局部域,若没有访问到则访问全局域,若全局域还没有访问到,报错!

2.如果指定了域。直接去指定的域访问,若没有访问到,报错!

这里没有指定域,所以编译器先后去局部域和全局域搜索都搜索不到rand的定义,所以报错!


那么如何解决,有三种办法,请看:


1.加命名空间名称及作用域限定符::

#include<stdio.h>
namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}
int main()
{
	printf("%d\n", HD::rand);
	printf("%d\n", HD::LCD::i);
	return 0;
}

 

作用域限定符:: 就是指定域用的。如果作用域限定符::前面为空,那么默认指定访问全局域,如:

#include<stdio.h>
namespace HD
{
	int rand = 10;
}
int rand = 100;
int main()
{
	int rand = 1000;
	printf("%d\n", HD::rand);
	printf("%d\n", ::rand);
	printf("%d\n", rand);
	
	return 0;
}

第一个打印10,因为指定了域,所以直接去命名空间域HD搜索了!

第二个打印100,因为指定了域,所以直接去全局域搜索了! 

第三个打印1000,因为没有指定域,所以优先访问局部域且访问到了rand。


2. 使用using将命名空间中某个成员引入

#include<stdio.h>
namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}
using HD::rand;
using HD::LCD::i;
int main()
{
	printf("%d\n", rand);
	printf("%d\n", i);
	return 0;
}

这个被引入的成员能在编译器访问全局域的时候被访问到! 

 


3.使用using namespace 命名空间名称引入 

#include<stdio.h>
namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}
using namespace HD;
using namespace HD::LCD;
int main()
{
	printf("%d\n", rand);
	printf("%d\n", i);
	return 0;
}

那么这个命名空间的全部成员都可以在编译器访问全局域的时候被访问到! 

 

本鼠顺便提一嘴,这种方式慎用,因为这样就将命名空间成员全部引入了,那样子命名空间不就形同虚设了咩!!!控制不好很容易导致命名冲突!


介绍完了三种命名空间的使用方法,本鼠考考读者老爷们,下面代码运行结果是什么:

#include<stdio.h>
namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}
using namespace HD;
int main()
{
	int rand=100;
	printf("%d\n", rand);
	return 0;
}

本鼠认为结果是打印100。因为即使使用using namespace HD引入,将命名空间HD的成员都引入了。但编译器对于没有指定域的话,优先访问局部域,那么局部域有变量rand的定义当然打印100了。

如果访问局部域没有找到rand的定义,那么编译器会访问全局域。由于使用了using namespace HD引入,所以编译器在访问全局域的时候能访问到命名空间HD的成员rand。

#include<stdio.h>
namespace HD
{
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	//嵌套命名空间
	namespace LCD
	{
		int i = 100;
		struct LCD
		{
			int age;
			double weight;
			struct LCD* next;
		};
	}
}
using namespace HD;
int main()
{
	int RAND=100;
	printf("%d\n", rand);
	return 0;
}

 


 3.C++的输入&&输出

本鼠写一个C++版本的Hello world!来讲解:

#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
	cout << "Hello world!" << endl;
	return 0;
}

要看懂这个代码,要了解:

1.std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中。

2.coutcin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。

3.cout标准输出对象(控制台)可以笼统认为等于C语言的printf,cin标准输入对象(键盘)可以笼统认为等于C语言的scanf,endl可以笼统认为等于C语言的换行符"\n"。

4.使用cout标准输出对象(控制台)cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。

5.C++中<<是流插入运算符,>>是流提取运算符。当然C++兼容C语言的大部分语法,所以<<在C++中也可以是左移操作符,>>在C++中也可以是右移操作符。

6.使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。 C++的输入(cin)输出(cout)可以自动识别变量类型。


那么看完上面6点,看结果:

其实很形象的,”Hello world!“ 和endl依次顺着<<”流入“cout打印在控制台上咩!

我们看到打印"Hello world!"并不用像C语言那样手动控制格式“%s”,自动识别了!


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


std命名空间的使用惯例: std是C++标准库的命名空间,如何展开std使用更合理呢?

1. 在日常练习中,建议直接using namespace std即可,这样就很方便。

2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对 象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模 大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。


4.缺省参数

4.1缺省参数概念

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

#include<iostream>
using namespace std;
void Func(int a = 10)
{
	cout << a << endl;
}
int main()
{
	Func();// 没有传参时,使用参数的缺省值
	Func(100);// 传参时,使用指定的实参
	return 0;
}

 简单易懂好吧!

 

 缺省参数有几点注意事项:

1.缺省参数不能在函数声明和定义中同时出现,当函数声明和定义分离时在声明给缺省参数。

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

3.C语言不支持(编译器不支持)缺省参数。

4.2.缺省参数的分类


1.全缺省参数

就是为函数所有参数指定了一个缺省值,如:

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

2.半缺省参数

就是为函数部分参数指定了一个缺省值,如:

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

要注意半缺省参数必须从右往左依次来给出,不能间隔着给 。


 调用一个看看:

#include<iostream>
using namespace std;
void Func(int a , int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
int main()
{
	Func(1,10);
	return 0;
}

这里函数Func参数a没有指定缺省值,所有调用Func函数的时候必须给a一个实参,b、c随便。

 


5.函数重载

5.1.函数重载概念

 C语言不支持同名函数,但是C++支持。因为C++有:

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


1.参数类型不同构成函数重载

#include<iostream>
using namespace std;
int Add(int a = 10, int b = 20)
{
	cout << "Add(int a=10,int b=20)->";
	return a + b;
}
double Add(double a = 10.0, double b = 10.0)
{
	cout << "Add(double a=10.0,double b=10.0)->";
	return a + b;
}
int main()
{
	cout << Add(5, 5) << endl;
	cout << Add(10.0, 9.9) << endl;
	return 0;
}

编译器会根据传入实参类型不同调用相应的Add函数。 


 2.参数个数不同构成函数重载

#include<iostream>
using namespace std;
void Func(int a,int b)
{
	cout << "Func(int a,int b)"<<endl;
	
}
void Func(int a,int b,int c)
{
	cout << "Func(int a,int b,int c)"<<endl;
}
int main()
{
	Func(1, 2);
	Func(1, 2, 3);
	return 0;
}

 编译器会根据传入实参个数不同调用相应Func函数。


3.参数类型顺序不同构成函数重载

#include<iostream>
using namespace std;
void Func(int a,double b)
{
	cout << "Func(int a,double b)"<<endl;
	
}
void Func(double a,int b)
{
	cout << "Func(double a,int b)"<<endl;
}
int main()
{
	Func(1, 2.2);
	Func(1.1, 2);
	return 0;
}

编译器会根据传入实参类型顺序不同调用相应Func函数。 


 5.2.C++支持函数重载的原理--名字修饰(name Mangling)

本鼠也说不是很清楚,本鼠大概知道原理。所以本鼠大概讲讲,如有不足,恳请斧正!

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

C语言编译器在链接时,直接根据函数名去找函数地址。由于函数名相同,导致找到多个地址,编译器不知道该链接哪一个地址,所以不支持函数重载。

C++编译器有函数名修饰规则(这个规则不统一,各个编译器可能不同),会引入函数参数类型信息添加到修改后的函数名中,只要参数不同,修饰出来的名字就不一样,那么找到的地址就不同,就支持函数重载了!

本博客就到这里吧,感谢阅读,下次再见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

URL路由基础

本书1-7章样章及配套资源下载链接: https://pan.baidu.com/s/1OGmhHxEMf2ZdozkUnDkAkA?pwdnanc 源码、PPT课件、教学视频等&#xff0c;可以从前言给出的下载信息下载&#xff0c;大家可以评估一下。 对于高质量的Web应用来讲&#xff0c;使用简洁、优雅的URL设计模式非常…

Vue进阶之Vue无代码可视化项目(三)

Vue无代码可视化项目 项目初始化store的使用DataSourceView.vuestores/counter.ts开发模式按钮store/editor.tsLayoutView.vue导航条安装图标iconpackage.jsonstore/debug.tssrc/components/AppNavigator.vueAppNavigator.ts:AppNavigator.vue:theme样式theme/reset.csstheme/v…

浅谈正向代理和反向代理(案例介绍)

公司一般主要以反向代理为主(最典型的Nginx负载均衡) 一、正向代理 客户端Client不直接访问服务器Server&#xff0c;通过代理服务器Proxy访问 正向代理是客户主动使用的代理 正向代理&#xff1a;最典型的案例就是通过爬虫爬取网络数据&#xff0c;如果请求次数过多该网站会…

十_信号13 - abort()

abort() 1 首先进程不能忽略 SIGABRT信号 2 要么在 SIGABRT信号的处理函数中 清理缓冲区并自己退出进程。如果信号处理函数中没有执行退出进程操作&#xff0c;返回到 abort()函数中&#xff0c;要求在 abort()函数中结束进程&#xff0c;不能返回到其调用者

[DDR5 Jedec 3-4] 模式寄存器 Mode Register MRR/MRW

依公知及经验整理,原创保护,禁止转载。 专栏 《深入理解DDR》 1. 概念 模式寄存器用于定义各种操作模式。在初始化过程中,可以通过重新执行MRS命令来更改模式寄存器的内容。即使用户只想修改模式寄存器变量的一个子集,在发出MRS命令时也必须编程所有变量。 只有当所有ban…

Netfilter/iptables

1. Netfilter组件图 https://en.wikipedia.org/wiki/Netfilter 其中&#xff1a; etables作用于数据链路层&#xff0c;arptables针对ARP, iptables/ip6tables针对IP层。 nftables 是新的包过滤组件. nft是相对应的新的用户态组件&#xff0c;用于替换etables,arptables,ipt…

支付宝支付(沙盒支付)

后端页面代码 Controller RequestMapping("/pay") public class PayController {private String orderId;Autowiredprivate OrdersService ordersService;Value("${appId}")private String appId;Value("${privateKey}")private String private…

字符串操作java

题目&#xff1a; 描述 给定长度为n的只有小写字母的字符串s&#xff0c;进行m次操作&#xff0c;每次将[l,r]范围内所有c1字符改成c2&#xff0c;输出操作完的字符串 输入描述&#xff1a; 第一行两个数n,m 第二行一个字符串s 之后m行&#xff0c;每行两个数l 、r两个字符…

基础—SQL—DCL(数据控制语言)小结

一、总结 在SQL分类中的DCL语句部分&#xff0c;主要讲到了两个部分的知识。 1、用户管理 用户管理&#xff0c;主要是管理哪些用户可以访问当前 mysql 数据库。 包括&#xff1a;创建用户、修改用户密码以及删除用户 2、权限控制 权限管理&#xff0c;主要是控制我们当前用户…

微软云计算之云计算平台、云操作系统Windows Azure

微软云计算平台 微软云计算平台微软的云计算技术Windows Azure组成 微软云操作系统Windows AzureWindows Azure概述Windows Azure计算服务Windows Azure存储服务全局命名空间体系架构存储域的层次结构双复制引擎文件流层分区层 Windows Azure ConnectWindows Azure CDNFabric控…

安卓组合控件(底部标签栏、顶部导航栏、增强型列表、升级版翻页)

本章介绍App开发常用的一些组合控件用法&#xff0c;主要包括&#xff1a;如何实现底部标签栏、如何运用顶部导航栏、如何利用循环视图实现3种增强型列表、如何使用二代翻页视图实现更炫的翻页效果。 底部标签栏 本节介绍底部标签栏的两种实现方式&#xff1a;首先说明如何通…

Linux系统tab键无法补齐命令-已解决

在CentOS中&#xff0c;按下tab键就可以自动补全&#xff0c;但是在最小化安装时&#xff0c;没有安装自动补全的包&#xff0c;需要安装一个包才能解决 bash-completion 1.检查是否安装tab补齐软件包&#xff08;如果是最小化安装&#xff0c;默认没有&#xff09; rpm -q ba…

提莫攻击 ---- 模拟算法

题目链接 题目: 分析: 如果两次攻击的时间差是>中毒的持续时间duration, 那么第一次攻击的中毒时间就是duration如果两次攻击的时间差是< 中毒的持续时间duration, 那么第一次攻击的持续时间就是这个时间差假设攻击了n次, 那么我们从第一次攻击开始计算时间差, 那么当我…

Halo DB 魔法之 pg_pcpu_limit

↑ 关注「少安事务所」公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ 前情回顾 前面已经介绍了“光环”数据库的基本情况和安装办法&#xff0c;今天来介绍一个新话题。 哈喽&#xff0c;国产数据库&#xff01;Halo DB! 三步走&#xff0c;Halo DB 安装指引 ★ Ha…

C++ A (1020) : 幂运算

文章目录 一、题目描述二、参考代码 一、题目描述 二、参考代码 #include<bits/stdc.h> using namespace std; typedef long long ll;void qq(ll a, ll b, ll m) {if (a 0) cout << 0 << endl;;ll out 1;a % m;while (b > 0){if (b & 1)//奇数的最…

LeetCode17电话号码的字母组合

题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 解析 广度优先遍历或者深度优先遍历两种方式&#xff0c;广度优先…

【OpenHarmony】TypeScript 语法 ④ ( 函数 | TypeScript 具名函数和匿名函数 | 可选参数 | 剩余参数 | 箭头参数 )

文章目录 一、TypeScript 函数1、TypeScript 具名函数和匿名函数2、TypeScript 函数 与 JavaScript 函数对比3、TypeScript 函数 可选参数4、TypeScript 函数 剩余参数5、TypeScript 箭头函数 参考文档 : <HarmonyOS第一课>ArkTS开发语言介绍 一、TypeScript 函数 1、Typ…

PHP MySQL图解学习指南:开启Web开发新篇章

PHP曾经是最流行的Web开发语言&#xff0c;许多世界领先的网站(如Facebook、维基百科和WordPress)都是用它编写的。PHP运行在Web服务器端&#xff0c;通过使用存储在MySQL数据库中的数据&#xff0c;使得网站可以为每一位访问者显示不同的定制页面。书中采用简单、直观的图示化…

bootstrap5-学习笔记2-模态框+弹窗+tooltip+popover+信息提示框

参考&#xff1a; Bootstrap5 教程 | 菜鸟教程 https://www.runoob.com/bootstrap5/bootstrap5-tutorial.html Bootstrap 入门 Bootstrap v5 中文文档 v5.3 | Bootstrap 中文网 https://v5.bootcss.com/docs/getting-started/introduction/ 之前用bootstrap2和3比较多&#x…