C++基础(命名空间,输入输出流,缺省参数,函数重载)

前言

C++是在C语言的基础上提出的,本节将区分C与C++的一些相似且易错的知识点,进行过渡的同时,为接下来的C++学习奠定基础。

C++关键字

C++是在C语言基础之上产生的,所以C++的关键字包含了很多C语言的关键字,这也说明C++是兼容C语言的。
C++的关键字有63个:
asm,do,if,return,try,continue,auto,double,inline,short,tepedef,for,bool,dynamic_cast,int,signed,typeid,for,public,break,else,long,sizeof,typename,throw,case,enum,mutable,static,union,wchar_t,catch,explicit,namespace,static_cast,unsigned,default,char,export,new,struct,using,friend,class,extern,operator,switch,virtual,register,const,false,private,template,void,true,const_cast,float,protected,this,volatile,while,delete,goto,reinterpret_cast

命名空间

作用

C++的引入是在C语言的基础上的,所以引入的东西也都是C语言所缺陷的,在C语言中没有命名空间这一说法,使得我们无法使用C语言提供的函数名作为参数名,举一个栗子:

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
	int printf = 10;
	printf("%d", printf);
}

这一段程序是不正确的程序,由于printf是已经在stdio.h中定义过的函数名,不能再使用它作为变量名了。
在一个公司中,一个工程往往都是好多人一起来完成的,这就可能出现,两个人定义了相同名称的变量,但是他们都不知道造成一定的麻烦,因此C++引入命名空间这一概念,来使得可以定义相同名称的变量而不会产生冲突

命名空间的使用

命名空间是定义在全局中的,因此其中的变量都是存在内存中的静态区
使用命名空间就要使用关键字:namespace,下面就是命名空间的书写。

namespace llb
{
    
    
	int printf = 10;
	int Add(int left, int right)
	{
    
    
		return left + right;
	}
	struct Node
	{
    
    
		struct Node* next;
		int val;
	};
}

这样就定义了一个名叫llb的命名空间,它里面的内容可以是变量,函数也可以是结构体。
那么如何使用其中的变量呢,这就需要域作用限定符‘::’
只需要将代码改为:

printf("%d", llb::printf);

llb:printf表示的就是引用的printf是llb中的printf而不是全局或者主函数中的printf。打印的结果是:
在这里插入图片描述
引用其中的函数也是同理:
在这里插入图片描述
在引用结构体时注意,命名空间要放在struct的后面:

struct llb::Node a;

命名空间的原理

命名空间的原理与编译器的查找规则有关。对于这样一段代码:

printf("%d", a);

编译器在打印a这个变量的时候,首先会在主函数中去寻找a这个变量的值,如果没有找到就会在全局中(静态区)寻找,再没找到就会报错。这也说明了在全局中与主函数中定义的相同名字的变量,在使用的时候会首先使用主函数中定义的。
而命名空间既不在主函数中也不再全局中,必须进过::操作符的引用才能打印。
当加入lib::时,编译器就只会从该命名空间来查找这一变量了。

扫描二维码关注公众号,回复: 13714184 查看本文章

命名空间的展开

命名空间的展开指的就是将命名空间中的变量展开到全局中。

部分展开

使用using 可以进行空间的部分展开,举一个例子:

namespace llb
{
    
    
	int a = 20;
	int b = 30;
}
using llb::a;
int main()
{
    
    
	printf("%d", a);
}

在全局中加入using llb::a,即可在函数中不引用a来使用a,即a已经进入到了全局中,但是不能使用b,因为b没有进入全局中。

全部展开

使用using namespace可以进行命名空间的全部展开,但是需要慎用,因为全部展开之后命名空间将不再有意义。

namespace llb
{
    
    
	int a = 20;
	int b = 30;
}
using namespace llb;
int main()
{
    
    
	printf("%d", a);
	printf("%d", b);
}

在这里插入图片描述
全部展开有一个重要的应用,就是展开std域。
在书写C++程序时,我们经常会发现在开头都有这样一段代码:

#include<iostream>
using namespace std;
int main()
{
    
    
	cout << "Hello World!" << endl;
	return 0;
}

这是因为C++的函数都在std这个命名空间域中,与C语言不同,C语言是放在头文件stdio.h中。
这样做的目的是在某次使用时,想要使用C++中的函数作为变量,可以不写using namespace std,而直接使用C++的函数名作为变量。

C++的输入输出

C++的输出

C++的输出函数cout,又称标准输出流。

int a = 10;
	float b = 2.3;
	cout << "Hello World!" << endl;
	cout <<a<<endl<<b<<endl;

这段代码中<<表示的是输出运算符,endl表示的是换行。
cout相对于printf的好处就是不需要指定类型,这段代码如果使用C语言来打印:

printf("%d\n%f",a,b);

但是cout的缺点也很明显,就是无法规定保留小数的位数。所以在打印时也要选择合适的函数来进行选择。

C++的输入

C++的输入函数是cin:

cin >> a;
	cin >> b;
	cout<<a<<" "<< b;

cin为C++的输入函数,同样没有C语言那样取地址的麻烦。

缺省参数

定义

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

void Test(int a = 5)//定义缺省参数为5
{
    
    
	cout << a << endl;
}
int main()
{
    
    
	Test(4);//向形参传入实参4
	Test();//不向形参传参
	return 0;
}

打印的结果为:
在这里插入图片描述
当向形参中传入实参4时,最终a的值赋为4,当不向形参中传参时,a的值赋为默认值5。

全缺省参数

即所有参数都使用了缺省值:

void Test(int a = 5, int b = 10,float c=2.3)
{
    
    
	cout << a <<" " <<b<<" " <<c << endl;
}
int main()
{
    
    
	Test(4,3,3.4);
	Test(4,3);
	Test();
	return 0;
}

此时打印的结果为:
在这里插入图片描述
当所有形参均传入参数时,打印结果为形参的值;
当传入的值小于形参数时,从左向右依次匹配,其他传入默认值;
当不向形参传值时,打印的结果为默认形参值。

半缺省参数

规定:必须从左向右缺省参数。

void Test(int a , int b = 10,float c=2.3)
{
    
    
	cout << a <<" " <<b<<" " <<c << endl;
}
int main()
{
    
    
	Test(4,3,3.4);
	Test(4, 3);
	Test(1);
	return 0;
}

参数传入依然是按从右向左的顺序,但是缺省参数必须是从左向右缺省:
在这里插入图片描述

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

void Test(int a=5);
void Test(int a=5 )
{
    
    
	cout << a ;
}

比如这样一段代码就是不正确的,正确的写法为:

void Test(int a);
void Test(int a=5 )
{
    
    
	cout << a ;
}

函数重载

函数重载的定义

我们知道在C语言中是不允许函数名是相同的,但是在C++中,函数名相同时被允许的,但是有一定的规则。
函数名相同的条件是:同名函数的形参列表必须不同(参数个数或类型或顺序)
举一个简单的例子:

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

这两个函数就构函数重载,因为满足参数个数不同这一条件。
同理:

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

这两个函数也构成函数重载的条件,满足参数顺序不同这一条件。

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

这两个函数满足参数类型不同这一条件。所以也构成函数重载。

int Add(int left, float right)
{
    
    
	return left ;
}
short Add(int left, float right)
{
    
    
	return left;
}

而这两个函数就不构成函数重载,虽然返回值不同,但不满足参数不同这一条件,所以不属于函数重载。

函数重载的原理

程序的处理步骤

在讲解函数重载原理之前,先复习一下程序的处理步骤,即如何从.cpp文件生成的.exe文件。
1.预处理:头文件展开,宏替换,预处理,条件编译,去掉注释。
2.编译:生成汇编代码。
3.汇编:将汇编代码转化成机器码。
4.链接:将生成的机器码文件链接起来。

原理(linux系统下)

(1)在C语言汇编代码中,如果要调用某一个函数(假设为f),通常写为:
call f(?) 在生成汇编代码的步骤中,?表示的是函数f的地址,但是在生成汇编代码时还不知道f的地址时什么,所以用’?'代替。
程序会在链接这一步骤生成的符号表中找到f的地址。并填入其中,但是如果有重名函数,那么f的地址就不止一个,所以C语言不支持 函数重载。

(2)而在C++的汇编代码中,如果调用函数f(),生成的f()名与其中的参数有关:
如果f()中没有参数,则会生成call fv(?)其中v表示没有参数。
如果f()中的参数为int,则会生成call fi(?)其中i为类型int的首字母。
此时fv(?)与fi(?)对应的符号表中的地址就可以查找了,可以填入,所以C++支持函数重载而C语言不支持。
以上只是在linux系统下,gcc编译器进行的操作内容,windows下回更加复杂一些,需要一定的汇编知识才能完全理解

猜你喜欢

转载自blog.csdn.net/qq_51492202/article/details/122312895