栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++中使用namespace与作用域

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++中使用namespace与作用域

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
未命名空间
// namespace后没有名字,直接{}
// 拥有静态生命周期
// 可以在一个文件中不连续,但不能跨文件
// 成员可以直接使用(因为不知道名空间没有名字),也不能用作用域运算符
int i;
namespace{
    int i;	//二义性
}
// 也可以嵌套
namespace local{
    namespace{
        int i;
    }
}
//这是可以的,直接方位i就是全局的,要名空间的方式: local:i = 123;
名空间的声明与指示using
//using declaration(声明):语句一次引入名空间的一个成员,可以出现在全局/局部作用域,
//名空间作用域及类作用域,类作用域中,只能指向基类成员。
//using directive(指示):一个名空间,可出现全局/局部作用域和名空间,但不能在类作用域,
//使得某个特定名空间所有名字可见,之后就无需添加前缀了。
//using指示具备将名空间提升到包含名空间本身和using指示的最近的作用域的能力
namespace A{
    int i,j;
}
void f()
{
    using namespace A;	//把A的名空间注入到全局作用域中
    cout << i*j << endl;
}
//另外一个示例
namespace ntest{
    int i=1,j=10,k=100;
}
int j = 20;
void main()
{
    using namespace ntest;
    ++i;	//ntest::i设定为2;
    ++j;	//二义性,是全局的,还是ntest不明确
    ++::j;	//全局的,::j = 21
    ++ntest::j;	//
    int k=200;	//
    ++k;		//
}
//综上,使用using指示可能导致二义性错误,此类错误在使用冲突名字才发现,这是延后检测,
//意味着可能在特定库使用很久后才爆发冲突。
//故使用using申明效果更好,当日,using指示也不是无用,在名空间本身的实现文件中,使用using还是非常好的
成员查找顺序
namespace A{
    int i;
    int k;
    class c1{
        public:
        	c1():i(0),j(0){};		//正确初始化c1类成员i,j
        	int f1() {return k;};	//返回A:k
        	int f2() {return h;};	//错误:h未定义
        	int f3();
        private:
        	int i;	//隐藏了A::i
        	int j;
    };
    int h = i;	//用A::i初始化
}
int A:c1:f3() {return h;} //正确,发回A::h

成员查找范围
std::string s;
std::cin >> s;
//以上的>>实际对应操作符: operate>>(std::cin, s) , 此处是如何调用到了呢

随意重载的隐患
//应用和标准库的冲突大部分是无意的,如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;
}
//如上,display函数从哪里来呢?
//首先查找本地(main函数内及本文件),之后实参查item,item属于test_item,item就从test_item及
//基类中查找,同时,NS中的声明的display也添加到候选集中。
重载与using
//using声明,声明的是一个名字,不是一个特定函数,如下:
 //当书写声明时,所有版本的函数都引入了当前作用域,故库作者如果选择性发布部分同名函数接口,
//可能导致外部调用异常(外部调用一个未显式提供的接口,结果也能用了)
//注意:如果using引入的函数和已有的同名且形参一样,using将引发错误

//using指示,将名空间成员提升到外层作用域中
namespace lib_us{
    extern void print(int);
    extern void print(double);
}
//普通声明
void print(const std::string &);
using namespace lib_us;	//此时print的候选集包括了如上的3个print

void foo(int a)
{
    print("test ok !!");//调用print(const std::string &)
    print(a);	//调用print(int)
}
//注意:如果此时namespace中的print版本和外部一样,并不出错,使用时指定名空间还是当前作用域就可以
跨越多个namespace函数集
//如果使用多个using指示,则每个名空间的名字都成为候选函数集的一部分,如:
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);	//调用aa:print
    print(1.1);	//调用bb:print
    return 1;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/928408.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号