C++中namespace的使用
概述
C++中使用namespace定义作用域,所有变量都有作用域,以往C中定义一个变量,
主要取决于定义的位置及修饰(如static),这样定义的作用域应用灵活度不高。
C++兼容以往的做法,但更推荐使用namespace来定义作用域。
且部分原来的C语法在C++已经被取消(如使用static定义局部静态变量已经被C++取消了,使用未命名空间取代),
以下就针对namespace的相关语法和使用做详细分析。
本文主要参考:C++ primer
namespace定义
namespace test{ //关键字namesapce + 名字
class test_data {/* */}; //类
int n = 1; //变量(及初始化)
extern float fExtVal; //外部域声明
int fn1(int x); //函数(及定义)
template <> struct hash; //模版
namspace other_name; //其他名空间
}//这个地方不要;
//名空间定义包括两部分:关键字namespace和名字,名字后面是{},包括声明和定义。
//名空间包含的内容主要包括如上.
名空间实质
1:名空间最基本的作用还是定义作用域
2:名空间中的每个名字都必须表示该空间的唯一实体,
不同名空间作用域不同,所以可以使用同名成员。
3:名空间中成员可以被名空间中其他成员直接访问
4;名空间可以不连续,如namespace test{},如test存在,就是添加新成员,
如不存在,就是定义一个新的名空间,这样就可以将名空间独立接口和具体实现组成一个名空间。
名空间的使用注意细节
1:不用把#include放在名空间中,因为这会把头文件中的所有名字定义为该名空间内部成员。
2:程序中某些实体只能定义一次:非内联函数,静态数据成员,变量等
3:全局命名空间:以隐式方式声明,且所有程序有存在,名字被隐式添加到全局命名空间中,
因为全局作用域是隐式的,所以使用这样的形式 ::member_name
嵌套名空间
namespace test{
namespace test-1{
class cTest1{/* */};
int a;
}
namespace test-2{
class cTest1{/* */};
class cTest3 : public cTest1 {/* */};
//.....
}
}
//如上,test分隔为两个,内层名空间隐藏外层名空间同名成员,如上的cTest1,
//嵌套的名空间只能使用内层的名字,外层的名空间要访问,必须添加名字限定符,如:test:test-1:cTest1
内联名空间
//不同处:内联名空间名字可直接被外层名空间直接使用,无需前缀
//文件intest.h
inline namespace InTestName{ //inline必须在名空间第一次出现的地方定义,后续可以不用
}
....
namespace InTestName{ //隐式内联
class Quary{};
//
}
//文件comtest.h
namespace ComTestName{ //非内联空间
class Quary{};
class other{};
//
}
//现假设一个名空间Maintest拥有两个
namespace Maintest{
#include "intest.h"
#include "comtest.h"
}
//因为InTestName是内联的,可以Maintest:Quary直接访问InTestName的成员,
//而如果访问ComTestName,必须要:Maintest:ComTestName:Quary
未命名空间
int i;
namespace{
int i;
}
namespace local{
namespace{
int i;
}
}
名空间的声明与指示using
namespace A{
int i,j;
}
void f()
{
using namespace A;
cout << i*j << endl;
}
namespace ntest{
int i=1,j=10,k=100;
}
int j = 20;
void main()
{
using namespace ntest;
++i;
++j;
++::j;
++ntest::j;
int k=200;
++k;
}
成员查找顺序
namespace A{
int i;
int k;
class c1{
public:
c1():i(0),j(0){};
int f1() {return k;};
int f2() {return h;};
int f3();
private:
int i;
int j;
};
int h = i;
}
int A:c1:f3() {return h;}
成员查找范围
std::string s;
std::cin >> s;
//以上的>>实际对应操作符: operate>>(std::cin, s) , 此处是如何调用到了呢
/*
1:隐藏规则有个重要例外:给函数传递一个类类型兑现时,除常规作用域查找外,还会查找实参所属名空间
2:针对1分析,调用operate时,首先当前作用域查找该函数,没找到,之后在参数所属的std和string的空间查找,
最后就找到string里面的operate函数。
3:针对1,2,要使用非成员函数时,有3种方式:
1:using std::operate>>; //先声明后使用
2:std::operate>>(std::cin,s); //显示指定
3: operate>>(std::cin, s); //隐式指定,靠参数cin和s的名空间内的接口
*/
随意重载的隐患
/* 如果代码中定义了一个标准库接口,在调用这个接口的时候,可能会:
1:基于重载规则,决定执行的版本
2:执行本地定义的,不执行标准库
*/
//应用和标准库的冲突大部分是无意的,如move接口,因此,最好使用带限定语的完整版本,如:
std::move // 而不是move
候选函数集
namespace NS{
class ctest{};
void display(const ctest& ) {};
}
class test_item : public NS::ctest {};
int main()
{
test_item item;
display(item);
return 0;
}
重载与using
namespace lib_us{
extern void print(int);
extern void print(double);
}
void print(const std::string &);
using namespace lib_us;
void foo(int a)
{
print("test ok !!");
print(a);
}
跨越多个namespace函数集
namespace aa{
int print(int);
}
namespace bb{
double print(double);
}
using namespace aa;
using namespace bb;
long double print(long double);
int main()
{
print(1);
print(1.1);
return 1;
}