之前在学习C++的时候,一直没有深入了解命名空间的相关事宜,这里重新学习一下C++的命名空间
1. C语言的缺陷
1.1 全局变量引用问题:
定义二个文件:
main.c
int a = 10
int main()
{
return 0;
}
test.c
int a = 11;
出现错误:
分析: 因为这里定义的int a = 10;
是一个全局变量,而且C语言是全局变量是跨文件的,所以引用该变量的时候,不知道要引用哪一个文件。
解决方法:
如果想要正常引用a这个变量,那么我们可以在test.c这个文件中将int a = 10;
变成了stataic int a =10
, 使用静态局部变量我们就可以让这个变量的作用域仅仅在这个文件中。
1.2 局部变量屏蔽全局变量的问题
#include<stdio.h>
int a = 1;//C 出现重名无法引用全局变量
void main()
{
printf("%d", a);
int a = 3;
printf("%d",a);
getchar();
}
在这个代码中,我们首先定义了全局变量,但是在main函数中我们定义了一个局部变量,这个变量对全局变量进行了覆盖了,所以在C语言中我们是没有办法输出这个全局变量的数值的,但是在C++中我们是可以得到这个数值的。
2. C++的命名空间
典型的C++模式代码:
#include<iostream>
int main()
using namespace std;
cout<<"hello world"<<endl;
return 0;
这里有几个问题:
1.为什么iostream不加上.h?
2. using namespace std什么东西?
关于命名空间,下面节选C++prime一段定义:
在c++中,名称可以是变量、函数、结构、枚举、类以及类和结构的成员。当随着项目的增大,名称相互冲突的可能性也会随之增大。使用多个厂商的类库时候,可能导致名称冲突。例如:两个类都定义了名称为List、Tree类,但定义的方式不兼容,用户可能想要使用一个库的List类,而使用另外一个类的Tree类。这种冲突被称为命名空间问题。
2. 1 定义自己的命名空间:
#include<iostream>
#include<stdlib.h>
namespace myspace
{
int a (15); //C++ 可以使用括号对变量进行初始化
void print() //在命名空间中我们可以使用添加函数
{
std::cout << "hello world"<<std::endl;
}
}
int main()
{
//std::cout输出, <<输出符,根据类型泛型转换为字符串输出
//std::endl;//换行,结束一个输出,
int a(5);
std::cout<<a<<std::endl; //输出一个局部变量
std::cout<<"mynamespace"<<myspace::a<<std::endl; //可以使用命名空间::变量名字进行访问
system("pause");
return 0;
}
2.2 匿名命名空间的使用
#include<iostream>
//匿名命名空间可以直接调用
namespace
{
int a(3);
void print()
{
std::cout << "gogogo";
}
}
int main()
{
std::cout << a; //如果一个命名空间没有定义名称那么可以直接调用这个命名空间,不需要使用::符号
print(); //可以直接调用
return 0;
}
2.3 命名空间的扩充
#include<iostream>
#include<stdlib.h>
namespace mynamespace
{
int a(5);
}
namespace mynamespace
{
int b(6);
}
int main()
{
std::cout << mynamespace::a << std::endl<<mynamespace::b << std::endl;
system("pause");
return 0;
}
输出
5
6
命名空间的扩充只需要重新写一个同名的命名空间就行了。不过注意扩充的时候不要使用同一个变量名字,否则出现一个变量多次初始化的错误。
2.3 给一个命名空间取一个别名
就是上面的代码我们可以使用
namespace msp = mynamespace; //给命名空间起一个别名
使用命名空间的别名是当命名空间名字比较长的时候我们可以取一个简短的名字。
2.4 命名空间嵌套
#include <iostream>
#include<stdlib.h>
namespace runrunrunrun
{
int a(10);
namespace run //命名空间的嵌套
{
int a(9);
}
}
int main()
{
std::cout << runrunrunrun::run::a << std::endl;//命名空间可以嵌套
std::cout << runrunrunrun::a << std::endl;
system("pause");
return 0;
}
2.5 using namespace 使用方法
#include<iostream>
#include<stdlib.h>
namespace mydata
{
int a(6);
}
namespace yourdata
{
int a(8);
}
using namespace mydata;//using必须在命名空间的后面,作用域
//using如果变量重名,会出现不明确错误,加上命名空间修饰符
void go()
{
//命名空间如果在块语句内容,作用域是定义开始到块语句结束
std::cout << mydata::a << std::endl;
std::cout << a << std::endl; // 使用using的时候这个我们就不需要::符
}
//using namespace mydata;//作用域为从代码开始到结束
int main()
{
//std::cout << mydata::a << std::endl;
std::cout << yourdata::a << std::endl;
system("pause");
return 0;
}
这里注意几点:
1. using namespace + 某命名空间是使用该命名空间的全部内容,这个时候我们就不需要使用::
符号了。 比如最常见的我们没有使用using namespace std
那么我们输出的话就需要使用std::cout
但是我们使用std之后,就可以直接使用cout
代码了。
2. C++中我们使用#include<iostream>
不用.h原因就是iostream
里面包含了很多命名空间 了,有没有命名空间是区别C和C++的重要区别。
2.6 命名空间的使用举例
命名空间不仅仅可以解决变量全局变量冲突的问题。在迭代式开发中,假如我们需要开发一个新的功能,但是我们也需要保存旧的功能,这个时候我们可以利用命名空间辅助进行开发。
#include <iostream>
namespace runmove
{
int y(5);
int(*padd)(int, int);//函数指针接口
//private: 命名空间是透明的
int y1(5);
class myclass
{
public://类默认是私有,实现封装
int a;
};
}
int add(int a, int b)
{
return a + b;
}
int addp(int a, int b)
{
std::cout << a << b;
return a + b;
}
struct MyStruct
{
int b;//结构体默认是透明的
private:
int a;//是私有
};
int main()
{
//namespace所有数据,函数,类,对象都是共有
MyStruct struct1;//结构体内部默认公有
struct1.b;
return 0;
}
注意:
- 命名空间是所有内容透明的,不可以使用private私有变量;结构体默认是共有的,但是可以使用private;类默认是私有的,共有的话需要使用
public
关键字; - 在软件开发中,namespace一般不保存函数体,一般保存的是函数指针,这样的话我们不仅仅可以扩充新的功能,也具有良好的兼容性。
在回到开头的问题,C语言在使用局部变量屏蔽全局变量之后,是不能再访问全局变量了,在C++中我们可以利用命名空间解决这个问题。
#include<iostream>//C++没有.h加以区分C/C++
//C/C++头文件 有没有命名空间
#include<stdlib.h>
//int a = 1;
int main()
{
int a = 3; //局部变量覆盖全局变量
std::cout << ::a; //使用::默认使用全局的命名空间,这个时候我们就可以访问全局变量了。
system("pause");
return 0;
}
命名空间是C++一个重要的概念,之前也就是知道就这么写,但是也不知道为什么这么写,由于C++好久好久没有学习了,写起来还是很陌生。总是忘记打分号,好吧,python遗留下来的问题。