C++ 自定义namespace的使用技巧

时间:2026-02-15 13:55:29

1、       所谓分离式实现就是指“声明”和“定义”分别保存在不同的文件中,一般讲声明保存在.h文件、定义保存在.cpp文件中。如此放置便可达到分离式方式。

       那么将声明和定义分离有什么意义吗?首先从非分离式(声明的同时给出定义)看,其内容一般保存在.h文件中,以供多个源文件引用。但是将定义放在头文件,那么当多个源文件使用#include命令包含此类的头文件便会在链接阶段出现“multiple definition”链接错误!那么想让多个文件使用此头文件,又不引发链接的“multiple definition”错误该怎么办呢?

      分离式的实现便可以解决这个问题。因为.h文件中只包含声明,即使被多个源文件引用也不会导致“multiple definition”链接错误。所以分离式实现增强了命名空间的实用性。以下举例说明。(2015-04-11 更新)

2、//Two.h  定义

#ifndef TWO_H

#define TWO_H

#include <string>

using namespace std;

namespace MyNameSpace

{

    void Say();

}

namespace MyPrintSpace

{

    void Say();

}

#endif

3、//Two.cpp 实现

#include <iostream>

#include <string>

#include "Two.h"

using namespace std;

void MyNameSpace::Say()

{

    cout << "MyNameSpace::Say()" << endl;

}

void MyPrintSpace::Say()

{

   cout << "MyPrintSpace::Say()" << endl;

}

4、       #include "Two.h"预编译指令只引入了namespace的定义到当前文件中,此时还必须使用‘namespace_name::Identifier’的方式访问名称。

1.若想直接使用某个标识符,应该使用如下方法引入标识符:

using 命名空间标识符::标识符;

2.将namespace下面的所有标识符引入,可使用:

using namespace  命名空间标识符;

5、将自定义的namespace的实现和定义分别放在.cpp和.h文件中,达到分离式实现。Two.h文件用于命名空间的声明,Two.cpp文件用于命名空间中函数、类等的实现。

1、// One.cpp 测试文件

#include <iostream>

#include <string>

#include "Two.h"

using namespace std;

using namespace MyNameSpace;

using namespace MyPrintSpace;

void Say()

{

    cout << "Galobel::NameSpace" << endl;

}

int main()

{

    ::Say();  //全局命名空间::

    MyNameSpace::Say();

    MyPrintSpace::Say();

    return 0;

}

2、#编写Makefile文件

CC=g++

OBJS=One.o Two.o

NameSpace : ${OBJS}

    ${CC} -o NameSpace ${OBJS}

One.o : One.cpp Two.h

    ${CC} -c -o One.o One.cpp

Two.o : Two.cpp Two.h

    ${CC} -c -o Two.o Two.cpp

clean:

    rm NameSpace One.o Two.o

#Terminal中编译

$ make

g++ -c -o One.o One.cpp

g++ -c -o Two.o Two.cpp

g++ -o NameSpace One.o Two.o

3、运行结果:

$ ./NameSpace

Galobel::NameSpace

MyNameSpace::Say()

MyPrintSpace::Say()

1、using声明/using编译指令

     using std::cin;                   // using声明使特定的标识符可用

     using namespace std;      // using编译指令使整个名称空间可用

2、using编译指令和using声明的比较

        使用using编译指令导入一个名称空间中所有的名称与使用多个using声明是不一样的,而更像是大量使用作用域解析运算符。使用using声明时,就好像声明了相应的名称一样。

       如果某个名称已经在函数中声明了,则不能用using声明导入相同的名称。然而,使用using编译指令时,将进行名称解析,就像在包含using声明和名称空间本身小声明区域中声明了名称一样。

       如果使用using执行导入一个已经声明的名称,则局部名称将隐藏名称空间名,就像隐藏同名的全局变量一样。

       不过仍然可以像下面的示例那样使用作用域解析运算符:

3、namespace Jill

{

     double buket(double n) { ... }

     double fetch;

     struct Hill { ... };

}

char fetch;  // gloabl namespace,全局空间

int main( )

{

    using namespace Jill;  // 导入命名空间所有名称

    Hill Thrill;

    double water = bucktet(2);  // use Jill:bucket( )

    double fetch;   // 隐藏Jill::fetch

    cin >> fetch;   // local fetch

    cin >> ::fetch;  // 全局fetch

    cin >> Jill::fetch;  // Jill::fetch

}

int foom( )

{

    Hill top;   //错误

    Jill::Hill crest;  //valid

}

//

       假设名称空间和声明区域定义了相同的名称。如果试图使用using声明将名称空间的名称导入该声明区域,则这两个名称会发生冲突,从而出错。如果是会用using编译指令将该名称空间的名称导入该声明区域,则局部版本将隐藏名称空间版本。

//////////////////////////////////////////////////////////

注:以上内容摘录自《C++ Primer Plus(第6版)中文版》第9章 内存模型和名称空间 第328页

4、     一般说来,使用using声明比较使用using编译指令更安全,这是由于它(using declaration)只导入指定的名称。如果该名称与局部名称发生冲突,编译器将发出指示。using编译指令导入所有名称,包括可能不需要的名称。如果与局部名称发生冲突,则局部名称将覆盖空间版本,而编译器并不会发出警告。另外,名称空间的开放性意味着名称空间的名称可能分散在多个地方,这使得难以准确知道添加了哪些名称。

// in file One.h

namespace seek

{

     void Func();

}

//////////// end One.h /////////

// in file Two.h

namespace seek

{

     void Add(double a, double b);

}

//////////// end Two.h /////////

//

在文件One.h和Two.h中都有命名空间seek的声明,这种写法是正确的。

1、2015-04-02  第一次更新

2015-04-11  第二次更新

© 2026 海能知识库
信息来自网络 所有数据仅供参考
有疑问请联系站长 site.kefu@gmail.com