超前引用与命名空间

转载至 : http://www.cppblog.com/yycmmc/archive/2012/06/04/177427.html


一般情况下,类型要在使用前定义,但是在一些特殊情况下,这种要求无法满足,例如两个类相互包含, 即两个类互相使用对方提供的方法。 更一般的情况,类A和类B需要彼此互相引用,这样必然有一个类会先被定义,而另外一个类后被定义,这样在先被定义的类引用后被定义的类的时候,就导致了所谓的超前引用。

    使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突。在C++中,变量、函数和类都是大量存在的。如果没有命名空间,这些变量、函数、类的名称将都存在于全局命名空间中,会导致很多冲突。比如,如果我们在自己的程序中定义了一个函数toupper(),这将重写标准库中的toupper()函数,这是因为这两个函数都是位于全局命名空间中的。命名冲突还会发生在一个程序中使用两个或者更多的第三方库的情况中。此时,很有可能,其中一个库中的名称和另外一个库中的名称是相同的,这样就冲突了。这种情况会经常发生在类的名称上。比如,我们在自己的程序中定义了一个Stack类,而我们程序中使用的某个库中也可能定义了一个同名的类,此时名称就冲突了。namespace关键字的出现就是针对这种问题的。由于这种机制对于声明于其中的名称都进行了本地化,就使得相同的名称可以在不同的上下文中使用,而不会引起名称的冲突。或许命名空间最大的受益者就是C++中的标准库了。在命名空间出现之前,整个C++库都是定义在全局命名空间中的(这当然也是唯一的命名空间)。引入命名空间后,C++库就被定义到自己的名称空间中了,称之为std。这样就减少了名称冲突的可能性。我们也可以在自己的程序中创建自己的命名空间,这样可以对我们认为可能导致冲突的名称进行本地化。这点在我们创建类或者是函数库的时候是特别重要的。

新建类A、类B分别放在NA、NB命名空间下:

// A.h
#pragma once

namespace  NA{

class  A{

private :
    B
*  m_b;

public :
    A(
void );
    
~ A( void );
    
void  A_DoSomething(){
        
this -> m_b -> B_DoSomething();
    }
};

}

 

// B.h
#pragma once

namespace  NB{
class  B
{
public :
    B(
void ){
    }
    
~ B( void ){
    }
    
void  B_DoSomething(){

    }
};

}

 

   因为在类A 中引用了B类,所以要在类A中包含B的头文件,并且声明类B,对类A作如下修改:


 

#pragma once

#include  " B.h "                          // STEP 1 : 包含要用到类的头文件

class  B;                                 // STEP 2 : 声明 要超前引用的

namespace  NA{

class  A{

private :
    B
*  m_b;

public :
    A(
void );
    
~ A( void );
    
void  A_DoSomething(){
        
this -> m_b -> B_DoSomething();
    }
};

}

 


此时,满怀信心的编译一下,一定会令你失望!提示编译错误,如图1(VS2010中):

                        图1 

                        图2 

错误指出,在该类B下找不到要用到的方法B_DoSomething(),尝试将类B的声明移动到命名空间NA中,发现一个奇怪的现象,如图3

                              图3

编译器认为,类B声明在命名空间NA下,由此分析,如果类B的声明在命名空间NA之外的话,编译器就认为类B的声明在全局命名空间中,而在全局命名空间下是不存在类B的,找不到B的方法也就不足为奇了,为此继续修改类A,将类B的声明限定在其所在命名空间NB下,如下所示:

 

#pragma once

#include  " B.h "                          // STEP 1 : 包含要用到类的头文件

// class  B;                              // ERROR : 将类B声明在了全局命名空间下

namespace  NB{                      // STEP 2 : 将该类声明在其所在命名空间下
     class  B;                            // OK : 将类B声明在了NB命名空间下
}

namespace  NA{

class  A{

private :
    B
*  m_b;

public :
    A(
void );
    
~ A( void );
    
void  A_DoSomething(){
        
this -> m_b -> B_DoSomething();
    }
};

}

 


此时,大功似乎告成,编译下,仍有错误,如图4所示:


提示找不到类B的声明,回头一想,应该声明所在的命名空间吧,于是添加 using namespace NB; 重新编译,仍然出错,郁闷了,改为直接引用类名,即 using NB::B; 重新编译,意外通过了编译!如下完整代码:

 

#pragma once
// 超前引用不同命名空间下的不同类、变量、方法时,要限定命名空间

#include  " B.h "                               // STEP 1 : 包含要用到类的头文件

// class B;                                   // ERROR : 将类B声明在了全局命名空间下
namespace  NB{                           // STEP 2 : 将该类声明在其所在命名空间下
     class  B;                                 // OK : 将类B声明在了NB命名空间下
}

// using namespace NB;                // ERROR!!
using   NB::B;                             // STEP 3 : 直接声明使用在所在命名空间下的类

namespace  NA{

class  A{

private :
    B
*  m_b;

public :
    A(
void );
    
~ A( void );
    
void  A_DoSomething(){
        
this -> m_b -> B_DoSomething();
    }
};

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值