c++命名空间和函数重载(详解)

目录

1.命名空间

        1.1定义命名空间

         2.2命名空间的使用

2.cout和cin的使用

3.缺省参数

        3.1定义

        3.2缺省参数分类 


1.命名空间

         在c++中有大量的变量,关键字和函数,为了防止命名冲突和名字污染的问题所以c++中引入了命名空间的概念。使用命名空间的目的是对标识符进行本地化,如下:

#include<iostream>
#include<stdio.h>
int rand = 10;
int main()
{
	printf("%d ", rand);//打印rand的值
	return 0;
}

        上面程序运行的结果是什么呢?10吗? 程序会报错:

 如何解决这个问题呢?用namespace关键字定义命名空间就可以解决这个问题。

如下:

#include<iostream>
#include<stdio.h>
namespace b
{
	int rand = 10;
}
int main()
{
	printf("%d ", rand);
	return 0;
}

那么这个程序输出的结果是什么呢? 我们接着往下看!

怎么结果不是10呢,因为c++,默认的查找变量的规则是先局部域里面找 ,如果找不到再去全局域找。它不会去我们定义的命名空间里面去找变量的(函数等也是)。我们接着往下看:

        1.1定义命名空间

        使用关键字namespace+{}(命名空间的成员)来定义命名空间,如下:

namespace bit
{
	int rand = 20;
	struct stu
	{
		char a[3];
		int age;
	};
	namespace b
	{
		int l = 10;
		char c = 20;
	}
}
int main()
{
	//使用命名空间的原因:在C语言和c++中存在大量的函数和变量以及类,这些变量,函数,以及类的名称都存在于全局作用域中
	//可能会导致很多冲突,使用命名空间的意义就是对标识符的名称进行本地化,防止命名冲突和名字污染
	//用namespace关键字来定义命名空间--命名空间就像一堵墙将命名空间中的变量函数等与全局域隔离开
	//c++官方标准的命名空间是std
	return 0;
}

这里是使用namespace关键字定义了一个bit的命名空间,那么你是否有这样的疑问命名空间里面可以定义哪些东西呢?如下:

#include<iostream>
#include<stdio.h>
namespace bit
{
	int a = 0;
	char c = 'a';//定义变量
	int arr[10] = { 0 };
	struct  stu//定义类型
	{
		char _id[10];
		double _weight;
	};
	void Print()//定义函数
	{
		struct stu as1 = { 0 };
		printf("hello world");
	}
	//......
}
int main()
{
	return 0;
}

        通过上面的例子我们发现命名空间里面可以定义变量,类型和函数等。我们接着往下看:

#include<iostream>
#include<stdio.h>
namespace bit
{
	int a = 0;
	char c = 'a';
	int arr[10] = { 0 };
	struct  stu
	{
		char _id[10];
		double _weight;
	};
	void Print()
	{
		struct stu as1 = { 0 };
		printf("hello world");
	}
	namespace byte//命名空间的嵌套
	{
		int c = 0;
		int d = 0;
	}
	//......
}
int main()
{
	return 0;
}

        我们发现命名空间还可以嵌套命名空间。 

        同一个工程中命名允许出现同名的命名空间,编译器最后会将同名的命名空间进行合并。例如:

//game.c
namespace bit
{
	double f = 0;
}
//test.c
#include<iostream>
#include<stdio.h>
namespace bit
{
	int a = 0;
	char c = 'a';
	int arr[10] = { 0 };
	struct  stu
	{
		char _id[10];
		double _weight;
	};
	void Print()
	{
		struct stu as1 = { 0 };
		printf("hello world");
	}
	namespace byte//命名空间的嵌套
	{
		int c = 0;
		int d = 0;
	}
	//......
}
int main()
{
	return 0;
}

         上面的game.c和test.c文件中的 bit最后会被编译器合并成为一个命名空间。

总结:一个命名空间其实就是定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。默认搜索是找不到这个命名空间中的内容的,这就像是给这个命名空间里面的内容加上了一堵高墙,命名空间之外的东西都是看不到命名空间里面的东西的,也访问不到命名空间里面的内容。(可以这样简答的理解)

        c++官方提供的标准命名空间是:std,关于c++标准库的东西都放在这个命名空间里面。

         2.2命名空间的使用

关于上面这个代码打印结果为什么不是10,怎么处理就会变成10呢?如下:

#include<iostream>
#include<stdio.h>
namespace b
{
	int rand = 10;
}
int main()
{
	printf("%d ", b::rand);
	return 0;
}

给rand前面加  b::rand,的意思是让编译器去指定的域里面找变量rand,如果没有找到就会报错,由此我们可以指定命名空间改变的是编译器的查找规则。如何没有加这个作用域的时候,编译器会在全局中找这个rand,由于rand是一个函数的函数名,所以以%d的形式打印,打印的结果就是一串数字也就是函数的入口地址。

        命名空间如何使用呢?有三种方式。

        1.全部展开(使用using namespace 命名空间名称引入)

        也可以叫做using编译指令

#include<iostream>
#include<stdio.h>
using namespace std;//全部展开
int main()
{
	cout << "hello world" << endl;
	int a = 10;
	cin >> a;
	cout << a << endl;
	return 0;
}

        不推荐使用,因为会暴露命名空间中的所有实体,如果不清楚命名空间中都有哪些实体就极易造成名字冲突(函数名,变量名或者类名)。 

        2.部分展开(使用using将命名空间中的某个成员引入)

        也就using声明机制。推荐使用,因为每次它只会展开命名空间中的一个变量,所以更加安全。

#include<iostream>
#include<stdio.h>
using  std::cout;//部分展开,这里只展开了cout
int main()
{
	cout << "hello world" << std::endl;
	int a = 10;
	std::cin >> a;
	cout << a << std::endl;
	return 0;
}

        3.指定(加命名空间以及域作用限定符(如果是空格表示全局域))

        这种方式是最安全的。

#include<iostream>
#include<stdio.h>
namespace b
{
	int rand = 10;
}
int main()
{
	printf("%d ", b::rand);//域名+域作用限定符
	return 0;
}

         总结:命名空间就是给这个命名空间里面的变量加上了一个限制,让命名空间外面对象和操作无法访问命名空间里面的内容,防止命名冲突和名字污染。这个命名空间相当于就是一堵墙,隔绝了墙里面和外面的内容,而访问命名空间里面的变量就相当于拆墙,全部展开就是直接将墙拆掉,部分展开就是只将一部分内容放在墙的外面,指定展开就是将指定的内容暴露出来。这样是相对安全的,全部展开不是很安全,但是在平时的使用中比较方便。

        1.3匿名命名空间

                1.3.1匿名命名空间的使用 

        大家肯定很好奇,既然有了命名空间,并且C++还是兼容C语言的那么C语言标准库中的变量和函数是放在哪里的呢,答案是它们都是放在匿名的命名空间中的。

        那么该如何访问匿名空间中的实体呢?

#include<iostream>
#include<stdio.h>
int main()
{
    //如果包含了C语言标准库的头文件,那么我们直接访问就行了,
    //比如使用printf()函数
    printf("hello world\n");
    //但是如果我们在main函数中定义了一个变量叫printf;
    int printf = 10;
    //这时候就无法使用全局的prinf(),如果想要使用就必须要指定命名空间的方式访问,因为局部的变量对于全局是由屏蔽作用的
     ::printf("how are you\n");//使用匿名的命名空间中的实体必须在域作用限定符号前面加一个空格
    return 0;
}

        使用匿名的命名空间中的实体必须在域作用限定符号前面加一个空格

                1.3.2匿名命名空间的性质

        大家都知道如果想要让一个函数或者一个全局变量只在本文件中可见,可以使用static修饰(static详解​​​​​​​),除了这种办法还有其它的办法吗?有的,使用匿名的命名空间也可以达到相同的效果

//a.cc

#include<stdio.h>
namespace 
{
int cnt = 0;
int add(int lhs, int rhs)
{
    return lhs + rhs;
}
}

//b.cc 

#include<iostream>
using namespace cout;
using namespace endl;
extern int ::add(int , int);//声明外部变量
int main()
{
    cout << add(3, 4) << endl;//此时会报错,即使已经声明add函数
    return 0
}

2.cout和cin的使用

        在C语言中我们使用printf函数输出内容到屏幕上,使用scanf函数从键盘上获取内容。那么在c++总我们是采用何种方式来进行输入和输出的呢?我们知道c++是兼容c语言的,但是c++也有自己的输入和输出操作 ,让我们一起来看看c++是如何实现自己的输入和输出的吧!

#include<iostream>
#include<stdio.h>
using std::cout;//将cout和cin展开
using std::cin;
int main()
{
	int a = 10;
	int b = 0;
	cin >> a >> b;
	cout << a << " " << b << " " << std::endl;
	return 0;
}

 解释:

1.cout是标准输出对象(控制台)cin标准输入对象(键盘),使用他们必须包含头文件iostream,以及按命名空间使用方法来使用std

2.cout和cin是全局的流对象,>>这是流插入操作符,<<这是流提取操作符。endl是换行,它是特殊的c++操作符,他们都包含在头文件iostream中。

3.使用cout和cin时更加方便,因为他们不需要输入参数类型就可以自动识别参数。printf和scanf需要自己手动控制格式。

4.实际上cout和cin属于ostream,istream类型的对象。

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

3.缺省参数

        3.1定义

        缺省参数是在声明或者定义函数时,给函数形参的一个缺省值,在调用该函数时如果没有传对应的参数那么就会使用这个缺省值, 否则使用传入函数的实参值。(在调用该函数时如果没有指定实参值,就使用缺省参数)缺省参数如何使用呢?如下:

#include<iostream>
#include<stdio.h>
using std::cout;//将cout和cin展开
using std::cin;
void Print(int a = 10, int b = 20, int c = 9)
{
	cout << a << " " << b << " " << c << " " << std::endl;
}
int main()
{
	Print(1);
	return 0;
}

        上面的函数就含有缺省参数。 

        3.2缺省参数分类 

        缺省参数分为全缺省和半缺省。如下: 

#include<iostream>
#include<stdio.h>
using std::cout;//将cout和cin展开
using std::cin;
void Print(int a = 10, int b = 20, int c = 9)
{
	cout << a << " " << b << " " << c << " " << std::endl;
}
int main()
{
	Print(1);
	return 0;
}

上面这个例子就是全缺省参数,我们来看看半缺省参数:

#include<iostream>
#include<stdio.h>
using std::cout;//将cout和cin展开
using std::cin;
void Print(int a, int b = 20, int c = 9)
{
	cout << a << " " << b << " " << c << " " << std::endl;
}
int main()
{
	Print(1);
	return 0;
}

注意,半缺省参数是部分缺省参数,不是缺省一半参数。

1.(半缺省)含有缺省参数的函数调用的时候,实参是从左向右赋值给形参的,而含缺省参数的函数,缺省值是从右向左定义的 。

2.不能间隔定义缺省参数,传值的时候也不能间隔传值。

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

4.C语言是不支持缺省参数的

下面举几个错误的例子。

栗子1,含半缺省参数的函数定义错误:

#include<iostream>
#include<stdio.h>
using std::cout;//将cout和cin展开
using std::cin;
void Print(int a=10, int b, int c = 9)
{
	cout << a << " " << b << " " << c << " " << std::endl;
}
int main()
{
	Print(1);
	return 0;
}

栗子2,传参时,间隔传参: 

#include<iostream>
#include<stdio.h>
using std::cout;//将cout和cin展开
using std::cin;
void Print(int a=10, int b=23, int c = 9)
{
	cout << a << " " << b << " " << c << " " << std::endl;
}
int main()
{
	Print(1,,3);
	return 0;
}

        好了今天的分享就到这里了,希望大家都可以有所收获。 

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值