Namespaces

when two identifiers (variable and/or function names) with the same name are introduced into the same scope. When this happens, anaming collision will result, and the compiler will produce an error because it does not have enough information to resolve the ambiguity. As programs get larger and larger, the number of identifiers increases linearly, which in turn causes the probability of naming collisions to increase exponentially.


Let’s take a look at an example of a naming collision. In the following example, foo.h and goo.h are the header files that contain functions that do different things but have the same name and parameters.

foo.h

<span style="font-size:18px;">// This doSomething() adds the value of its parameters
int doSomething(int x, int y)
{
    return x + y;
}

</span>

goo.h

<span style="font-size:18px;">// This doSomething() subtracts the value its parameters
int doSomething(int x, int y)
{
    return x - y;
}

</span>

main.cpp:

<span style="font-size:18px;">#include <foo.h>
#include <goo.h>
#include <iostream>
 
int main()
{
    using namespace std;
    cout << doSomething(4, 3); // which doSomething will we get?
    return 0;
}

</span>

If foo.h and goo.h are compiled separately, they will each compile without incident. However, by including them in the same program, we have now introduced two different functions with the same name and parameters into the same scope (the global scope), which causes a naming collision. As a result, the compiler will issue an error:

c:\VCProjects\goo.h(4) : error C2084: function 'int __cdecl doSomething(int,int)' already has a body


What is a namespace?

A namespace defines an area of code in which all identifiers are guaranteed to be unique. By default, all variables and functions are defined in theglobal namespace. For example, take a look at the following snippet:

<span style="font-size:18px;">int g_x = 5;
int foo(int x)
{
    return -x;
}

</span>

Both g_x and foo() are defined in the global namespace.

In the example program above that had the naming collision, when main() #included both foo.h and goo.h, the compiler tried to put both versions of doSomething() into the global namespace, which is why the naming collision resulted.

In order to help avoid issues where two independent pieces of code have naming collisions with each other when used together, C++ allows us to declare our own namespaces via thenamespace keyword. Anything declared inside a user-defined namespace belongs to that namespace, not the global namespace.

Here is an example of the headers in the first example rewritten using namespaces:

foo.h:

<span style="font-size:18px;">namespace Foo
{
    // This doSomething() belongs to namespace Foo
    int doSomething(int x, int y)
    {
        return x + y;
    }
}

</span>
goo.h:
<span style="font-size:18px;">namespace Goo
{
    // This doSomething() belongs to namespace Goo
    int doSomething(int x, int y)
    {
        return x - y;
    }
}

</span>
Now the doSomething() inside of foo.h is inside the Foo namespace, and the doSomething() inside of goo.h is inside the Goo namespace. Let’s see what happens when we recompile main.cpp:
<span style="font-size:18px;">int main()
{
    using namespace std;
    cout << doSomething(4, 3) << endl; // which doSomething will we get?
    return 0;
}

</span>

The answer is that we now get another error!

C:\VCProjects\Test.cpp(15) : error C2065: 'doSomething' : undeclared identifier


What happened is that when we tried to call the doSomething() function, the compiler looked in the global namespace to see if it could find a definition of doSomething(). However, because neither of our doSomething() functions live in the global namespace any more, it failed to find a definition at all!

There are two different ways to tell the compiler which version of doSomething to use.

1>Accessing a namespace with the scope resolution operator (::)

The first way to tell the compiler to look in a particular namespace for an identifier is to use the scope resolution operator (::). This operator allows you to prefix an identifier name with the namespace you wish to use.

Here is an example of using the scope resolution operator to tell the compiler that we explicitly want to use the version of doSomething that lives in the Foo namespace:

<span style="font-size:18px;">int main(void)
{
    using namespace std;
    cout << Foo::doSomething(4, 3) << endl;
    cout << Goo::doSomething(4, 3) << endl;
    return 0;
}

</span>
2>The using keyword

The second way to tell the compiler to look in a particular namespace for an identifier is to use theusing keyword.

The using directive tells the compiler that if it can not find the definition for an identifier, it should look in a particular namespace to see if it exists there. For example:

<span style="font-size:18px;"> int main(void)
{
    using namespace std;
    using namespace Foo; // look in namespace Foo
    cout << doSomething(4, 3) << endl; // calls Foo::doSomething()
    return 0;
}

 </span>


The using namespace Foo line causes doSomething(4, 3) to resolve to Foo::doSomething(4, 3). 

You can still get naming collisions with using declarations:

<span style="font-size:18px;">int main(void)
{
    using namespace std;
    using namespace Foo; // look in namespace Foo
    using namespace Goo; // look in namespace Goo
    cout << doSomething(4, 3) << endl;
    return 0;
}

</span>

As you might have guessed, this causes an error:

C:\VCProjects\Test.cpp(15) : error C2668: 'doSomething' : ambiguous call to overloaded function

In this case, it couldn’t find doSomething() in the global namespace, so it looked in both the Foo namespace and the Goo namespace (and the std namespace). Since doSomething() was found in more than one namespace, the compiler couldn’t figure out which one to use.

Instead of a using directive, we could also have used a using declaration:

<span style="font-size:18px;">int main(void)
{
    using namespace std;
    using Foo::doSomething; // Tell compiler that doSomething() means Foo::doSomething()
    cout << doSomething(4, 3) << endl; // will resolve to Foo::doSomething()
    return 0;
}

</span>

The using keyword follows normal scope rules (just like variables) -- if declared inside a block, it has block scope (and is only valid within that block). If declared outside a block, it has global scope, and affects the whole file from that point forward.(***using 关键字遵守普通的作用域规则(和变量类似)--如果在一个块内声明,那么它只有块作用域(只在该块内有效))。

Using the using keyword judiciously can make your code neater and easier to read. Although the using keyword can be used outside of a function to help resolve every identifier in the file, this is highly discouraged, as it increase the chance of identifiers from multiple namespaces (and the global scope) conflicting, which somewhat defeats the point of namespaces in the first place.(***强烈建议不要在块外使用using 关键字,因为它将增加名字冲突。)

Note that putting a using statement outside of a block in a header means that it will end up in the global scope of every file that includes that header. This should definitely be avoided.

(***注意: 在一个头文件中的块外使用using语句将意味着它的作用域为包含该头文件的每个文件的全局作用域。应该避免这样做。)

Rule: Don’t use the “using” keyword in the global scope. This includes header files!

(Rule: 不要在全局作用域内使用using 关键字,也包括头文件 中)。





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值