namespace又名命名空间命名空间是体现c++的封装的一种形式

当然命名空间的名字要自己创建这样以后好搞(一般选用自己的名字)

在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全 局作⽤域中,可能会导致很多冲突。使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名 冲突或名字污染,namespace关键字的出现就是针对这种问题的。 c语⾔项⽬类似下⾯程序这样的命名冲突是普遍存在的问题,C++引⼊namespace就是为了更好的解决 这样的问题

namespace的定义

• 定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中 即为命名空间的成员。命名空间中可以定义变量/函数/类型等。

• namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下 ⾯的rand不在冲突了。

• C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。

局部域和全局域除了会影响 编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。 • namespace只能定义在全局,当然他还可以嵌套定义。

• 项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。

在c++的标准库中有一个叫做std的命名空间

std

std中有些常用的输入输出

比如:cin面向窄字符(标准的输入流)

<<:流插入运算符

>>:流提取运算符

endl:一个函数相当于一个换行,并且刷新缓冲区

cout:面像窄字符(标准的输出流)

cerr:错误     colg(日志)

......

创造出了命名空间之后我们要进行访问

这时候就要使用:

::--->域操作符     在其他变量的时候空间的名字+::都是放在前面的有特殊的(比如类的是放在类类行的中间如下)(class也类似)

这是我们的访问

namespace ozj
{
	struct stu
	{
		char name[20];
		int age;
		char sex[10];
		char addrest[30];
	};
}
int main()
{
	//命名空间进行初始化
	struct ozj::stu s1 = { "小欧",12,"ann","aaaa"};
	
	printf("%s %d %s %s\n", s1.name, s1.age, s1.sex, s1.addrest);

	return 0;
}

当然也可以采用这样的形式对空间的只进行访问

namespace ozj
{
	int a = 10;
	int b = 20;
	int c = 30;
	int d = 90;
	int e = 666;
}

//using namespace ozj;

using ozj::a;

int main()
{
	int a = 20;
	printf("%d\n", a);
	//printf("%d\n", b);
	int ab=ozj::a;
	std::cout << ab;
	return 0;
}

命名空间中也可以进行函数的创建和使用

namespace ozj
{
	int add(int x, int y)
	{
		return x+y;
	}
	int a = 20;
	int b = 646;
}

//using namespace ozj;
int main()
{
	int a = 10;
	int b = 10;
	printf("%d ",ozj::add(a, b));

	return 0;
}

命名空间也可以进行嵌套定义(但是要注意的是嵌套定义的访问会有些复杂)

namespace ozj
{
	namespace new1
	{
		int a = 10;
		int b = 20;
	}
	namespace new2
	{
		struct stu
		{
			char name[20];
			int age;
			char sex[9];
			char addrest[20];
		};
	}
	namespace new3
	{
		int add(int x, int y)
		{
			return x + y;
		}
	}
}

int main()
{
	struct ozj::new2::stu s1 = { "小欧",12,"男","山东省" };
	printf("new a=%d\n",ozj::new3::add(ozj::new1::a, ozj::new1::b));

	printf("姓名:%s | 年龄:%d | 性别:%s | 地址:%s\n",s1.name,s1.age,s1.sex,s1.addrest);
	
	return 0;
}

关键字:using 的使用

这个关键字的作用是可以访问命名空间的任何一个变量也可以对空间进行展开的操作

比如我想访问上面代码的某一个命名空间

这里写伪代码进行

using namespace ozj::new2;--->展开new2这个命名空间
using namespace ozj::new1;--->展开new1这个命名空间
using namespace ozj::new3;--->展开new3这个命名空间
using namespace ozj;--->注意一下

这里我展开了ozj这个命名空间我的内部还是有空间进行封锁如果我是使用这种写法上面的展开可以变一变

using namespace ozj;

using namespace new2;
using namespace new1;
using namespace new3;

也能够达到那样的效果

关于using的使用还有些要注意的地方

• 指定命名空间访问,项⽬中推荐这种⽅式。

• using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。

• 展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。

在相对于c语言中还有一些变化比较大的是增加了一些关键的名词

缺省参数

• 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参 则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数。(有些地⽅把 缺省参数也叫默认参数)

• 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左 依次连续缺省,不能间隔跳跃给缺省值。

• 带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。

• 函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值

这个在顺序比表中使用比较好刚开始我们就少了一部空间的判断的步骤

代码的运用:

using namespace std;

int ADD(int x = 10, int y=20, int z = 30)
{
	return x + y + z;
}
int main()
{
	//a=1,b=2,c=3;
	int a, b, c;
	a = 0, b = 0, c = 0;
	cin >> a >> b >> c;
	cout << "ADD()=" << ADD() << endl;//60
	cout << "ADD(a)=" << ADD(a) << endl;//51
	cout <<"ADD(a, b)="<< ADD(a, b) << endl;//33
	cout << "ADD(a, b, c)=" << ADD(a, b,c) << endl;//6
	return 0;
}

函数的重载

C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者 类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同 名函数的。


//函数重载//允许函数名相同(形参或者数据类型不同即可)
//namespace ozj
//{
//	namespace new1
//	{
//		int a = 10;
//		int b = 20;
//	}
//	namespace new2
//	{
//		struct stu
//		{
//			char name[20];
//			int age;
//			char sex[9];
//			char addrest[20];
//		};
//	}
//	namespace new3
//	{
//		int add(int x, int y)
//		{
//			return x + y;
//		}
//	}
//}

using namespace std;

int Add(int m, int n)
{
	return m + n;
}

double Add(double m, double n)
{
	return m + n;
}

int main()
{
	int a = 0, b = 0;
	double c = 0, d = 0;
	cin >> a >> b >> c >> d;
	cout<<"Add(int ,int)=" << Add(a, b) << endl;
	cout<<"Add(double,double)=" << Add(c, d) << endl;
	return 0;
}

引用的概念

引⽤的概念和定义 引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间。⽐如:⽔壶传中李逵,宋江叫"铁⽜",江湖上⼈称"⿊旋 ⻛";林冲,外号豹⼦头;

类型& 引⽤别名=引⽤对象

//引用&
using namespace std;
int main()
{
	int a = 10;
	int& ra = a;
	++ra;
	int& rra = a;
	int& rrra = rra;
	double b = 10.10;
	int& rb = (int&)b;
	//cout << ra << endl << a << endl<<rra<<endl<<rrra<<endl;
	cout << rb << endl<<b<<endl;
	return 0;
}

int main()
{
	const int a = 10;
	const int& ra = 20;
	const int& ba = a;

	double c = 1.222;
	const int& a = c;
	int d = (int)c;
	cout << c << endl<<a << endl <<d<< endl;
	return 0;
}

&这里有些注意的是如果进行变量的引用属于权限的平移

但是如果引用的常量要加上const进行修饰(否则权限会被放大)

如果&的是一个变量加上const这就是权限的缩小

权限的放大不能通过编译器会进行报错其他的可以通过

引用的特性

• 引⽤在定义时必须初始化

• ⼀个变量可以有多个引⽤

• 引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体

• 引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被 引⽤对象。

• 引⽤传参跟指针传参功能是类似的,引⽤传参相对更⽅便⼀些。

• 引⽤返回值的场景相对⽐较复杂,我们在这⾥简单讲了⼀下场景,还有⼀些内容后续类和对象章节 中会继续深⼊讲解。

• 引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引⽤跟其他 语⾔的引⽤(如Java)是有很⼤的区别的,除了⽤法,最⼤的点,C++引⽤定义后不能改变指向, Java的引⽤可以改变指向。

• ⼀些主要⽤C代码实现版本数据结构教材中,使⽤C++引⽤替代指针传参,⽬的是简化程序,避开 复杂的指针,但是很多同学没学过引⽤,导致⼀头雾⽔。

指针和引⽤的关系

C++中指针和引⽤就像两个性格迥异的亲兄弟,指针是哥哥,引⽤是弟弟,在实践中他们相辅相成,功 能有重叠性,但是各有⾃⼰的特点,互相不可替代。
• 语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。

• 引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。

• 引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。 • 引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。

• sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下 占4个字节,64位下是8byte) • 指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。

内联函数

关键字--->inline

• ⽤inline修饰的函数叫做内联函数,编译时C++编译器会在调⽤的地⽅展开内联函数,这样调⽤内联 函数就需要建⽴栈帧了,就可以提⾼效率。

• inline对于编译器⽽⾔只是⼀个建议,也就是说,你加了inline编译器也可以选择在调⽤的地⽅不展 开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适⽤于频繁 调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。

• C语⾔实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不⽅便调 试,C++设计了inline⽬的就是替代C的宏函数。

• vs编译器debug版本下⾯默认是不展开inline的,这样⽅便调试,debug版本想展开需要设置⼀下 以下两个地⽅。

• inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地 址,链接时会出现报错。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐