初识C++|关键字、命名空间、输入输出、缺省参数、函数重载

本文介绍了C++中命名空间的概念、定义与使用,以及与C语言的区别,包括关键字数量、输入输出库、缺省参数和函数重载的原理。
摘要由CSDN通过智能技术生成

C语言是面向过程的语言,而C++是在C基础上发展起来的面向对象的语言。C++补充了C语言语法的不足,以及对C语言设计不合理的地方进行了优化。在哪方面进行了优化呢?接下来我们将一起学习。

⒈关键字

C++总计63个关键字,C语言32个关键字。
在这里插入图片描述

⒉命名空间

⑴为什么会引入命名空间

在C/C++中,变量、函数和类都是大量存在的,并且都将存在于全局作用域中,可能会导致很多冲突。
下面这个代码能正常运行

#include<stdio.h>

int rand = 10;

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

但如果给这个代码新加一个头文件stdlib.h便会报错,结果如下:

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

int rand = 10;

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

在这里插入图片描述
这是因为头文件stdlib.h中有一个用于产生随机数的函数rand,因为同一个域内不能定义同名变量,这样就区分不开名字相同的变量和函数了,产生了命名冲突。C++使用命名空间则是为了对标识符的名称进行本地化,以避免命名冲突或名字污染,,namespace关键字的出现就是针对这种问题的。

C++中有四种域:全局域、局部域、命名空间域、类域。
使用:访问全局域时在变量前加域作用限定符::,访问局部变量不用指定,访问命名空间空间域在::前1加域名,访问类域在::前加类名。
命名空间内的变量仍是全局的,它只是对全局冲突变量的隔离,不影响变量的生命周期,只影响访问。
编译器的搜索原则:(1)不指定作用域时:先在当前局部域搜索,没有再去全局域搜索;(2)指定作用域时直接去指定域搜索

⑵命名空间如何定义

定义命名空间时,需要使用到namespace关键字,后跟命名空间名,再加一对{},将变量写入里面就可以了。

//命名空间内可以定义变量、函数、结构体
namespace A  
{  
	int a = 1;
   	int Add(int left,int right)
   	{
		return left + right;
	}
	struct Node
	{
	 	int val;
	  	struct Node* next;
	};
   	.........
}

那么要修改上述代码就可以用以下方法解决了

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

namespace A
{
	int rand = 10;
}

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

命名空间的其他两种定义方法:
命名空间可以嵌套定义

//test.cpp
namespace B
{
	int b = 1;
   	int Add(int left,int right)
   	{
		return left + right;
	}
	namespace C
	{
		int c = 1;
   		int Sub(int left,int right)
   		{
			return left - right;
		}
   	.........
}

同一个工程允许存在多个名称相同的命名空间,编译后这几个空间的变量会放在一起.

//test.h
namespace B
{
   	int Mul(int left,int right)
   	{
		return left * right;
	}
}

注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

⑶命名空间如何使用

定义了一个命名空间,那么命名空间中的成员该如何使用呢?
看一下下面的代码是否正确?

namespace A
{
	int a = 0;
	int b = 1;
	int Add(int left ,int right)
	{
		return left + right;
	}
	struct Node
	{
		int val;
		struct Node* nexxt;
	};
}
int main()	
{
	struct Node phead;
	printf("%d\n",a);
	printf("%d\n",Add(1,2));
	return 0;
}

以上对变量的使用正确吗?
不正确,因为变量均未指定,按照编译器的搜索规则,先后在局部域和全局域搜索,都没有这些变量。

编译报错:
error C2065: “a”: 未声明的标识符
error C3861: “Add”: 找不到标识符
error C2079: “phead”使用未定义的 struct“main::Node”

那么应该怎么改呢?

①加命名空间名称及作用域限定符(指定使用)

如果是命名空间内的变量

printf(“%d\n”,a); --------------> printf(“%d\n”,A::a);

如果是使用命名空间内的函数

printf(“%d\n”,Add(1,2));----------->printf(“%d\n”,A::Add(1,2));

如果是使用命名空间内的结构体,与变量和函数不同,如下

struct Node phead; ----------> struct A:: Node phead;

②使用using将命名空间中某个成员引入(展开某一个)

using A::b

int main()
{
 	printf("%d\n",A::a);
 	printf("%d\n",b;  //将A中变量b引入,便可直接使用,不用加::
 	return 0;
 }

③使用using namespace命名空间名称引入(展开命名空间)

using namespace std; std是所有C++库的命名空间
即展开命名空间。

头文件展开和命名空间的展开一样吗
头文件展开:拷贝头文件内容
命名空间展开:公开声明,打开访问权限

using namespace A;

int main()
{
	printf("%d\n",b);
	Add(1,2);	
 	return 0;
}

⒊C++输入&输出

C++兼容C,所以在C++中,C语言的一套输入输出库我们仍然能使用,但是C++又增加了一套新的、使用更简单的输入输出库,即iostream库。
以下是一个标准的C++实现语句。

#include<iostream>
using namespace std;

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

说明:
①iostream库包含两个基础类型istream和ostream。cout是一个ostream类型的对象,称为标准输出对象,cin是一个istream类型的对象,称为标准输入对象,在命名空间std内定义。使用时必须包含头文件以及按命名空间使用方法使用std。
②cout和cin是全局的流对象,endl是特殊的C++符合,表示换行输出,它们都包含在头文件中。
③<<是左移运算符,当于cout搭配时是流插入运算符,>>是右移运算符,与cin搭配时称为流提取运算符。 在这里插入图片描述 在这里插入图片描述
C++能自动识别变量类型,不需要像printf/scanf那样手动控制格式。

⒋缺省参数(默认参数)

⑴缺省的概念

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

void Func(int a = 0)
{
	cout << a << endl;
}
int main()
{
	Func();  //没有传参
	Func(5); //传参

	return 0;
}

执行结果如下:
在这里插入图片描述

⑵缺省的分类

①全缺省参数:给每个函数参数都给一个缺省值

//定义
void Func(int a = 10, int b = 20, int c = 30)
{
	cout<<"a = "<<a<<endl;
	cout<<"b = "<<b<<endl;
	cout<<"c = "<<c<<endl;
}
int main()
{	//调用时有四种情况,不能跳着传参,比如Func(1, ,3);
	Func(1,2,3);  //结果是1 2 3
	Func(1,2);    //结果是1 2 30
	Func(1);      //结果是1 20 30
	Func();       //结果是10 20 30
	return 0;
}

②半缺省参数:不是说只给一半的参数给缺省值

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

注意事项:

·1.半缺省参数必须从右往左依次给出,不能间隔
·2.传参时是从左往右传
·3.缺省参数不能在函数声明和定义中同时出现(在声明中给出),防止声明和定义分离时编译阶段报错
·4.缺省值必须是常量或全局变量
·5.C语言不支持

⒌函数重载

⑴函数重载概念

C语言不允许同名函数存在,C++允许在同一作用域中声明几个功能类似的同名函数。这些同名函数的形参列表不同(参数的个数、类型、顺序不同),与返回值类型无关。
①参数类型不同

int Add(int left ,int right)
{
 	cout << "int Add(int left ,int right)" << endl;
	return left + right;
}
double Add(double left ,double  right)
{
 	cout << "double Add(double left ,double right)" << endl;
	return left + right;
}

②参数个数不同

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

③参数类型顺序不同

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;
}

int main()
{
	Add(10,20);
	Add(1.1,2.2);

	f();
	f(2);

	f(10,'a');
	f('a',10);
	return 0;
}

⑵C语言为什么不支持重载,而C++又为什么支持重载?

这就涉及到了程序的编译与连接过程以及函数名修饰规则。
C语言不支持重载,因为在链接时,直接用函数名去找地址,有同名函数,就无法区分
C++如何支持的呢?函数名修饰规则,名字中引入参数类型,各个编译器自己实现了一套。

①程序的编译与链接

程序编译为可执行文件的过程
分为四个阶段:预处理、编译、汇编、链接。下图是各阶段的作用和各阶段文件的类型。
以栈为例,有三个文件,Stack.h是定义栈结构和声明函数的文件,Stack.cpp是定义函数的文件,Test.cpp是用来测试函数功能的文件。
预处理阶段会生成Stack.i和Test.i这两个文件,因为预处理阶段在包含头文件的这两个文件内会Stack.h会被展开,宏被替换,注释被去掉;编译阶段,检查语法,生成Stack.s和Test.s文件;汇编阶段会进行将汇编代码转化为机器指令,生成一个符号表(符号表里有函数名和函数地址),并生成Stack.o和Test.o文件;最后在链接阶段,会将符号表合并和重定位,将Stack.o和Test.o链接成一个可执行程序a.out。
在这里插入图片描述

用函数名在符号表中查找函数的地址,有函数定义才有函数地址,否则报错。假设有函数定义,便找到了(2)。
在这里插入图片描述

②函数名修饰规则

以下面的Add函数与func函数为例,我们一起来看一下Linux系统中gcc和g++的函数名修饰是怎样的

//测试程序

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

void func(int a ,double b ,int* p)
{}

int main()
{
	Add(1, 2);
	func(1, 2, 0);
	return 0;

❶采用C语言编译器编译后结果
在这里插入图片描述
在这里插入图片描述

结论:在Linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。回答了C语言为什么不支持重载。

❷采用C++编译器编译后结果
在这里插入图片描述
在这里插入图片描述

结论:在Linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。回答了C++为什么支持重载。

在Linux环境下,C++的函数名修饰规则为【_Z + 函数长度 + 函数名 + 类型首字母】

了解一下在Windows环境下,C++的函数名修饰规则:
格式:【? + 函数名 + @@YA + 返回值 + 参数1 + 参数2 +@Z】
int类型对应的是字母H,void类型对应的是字母X,double类型对应的是字母N。
扩展:float类型对应的是字母M
在这里插入图片描述

今天就分享到这里,以上就是我整理的C++相比C语言优化的几个方面的内容,谢谢观看,有什么不对的地方还请指出~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天学习了吗•

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值