📄 ch08.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD> <META NAME="Author" Content="Steph Mineart"> <META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1"> <TITLE>ANSI/ISO C++ Professional Programmer's Handbook - Chapter 8 - Namespaces</TITLE> <link rel="stylesheet" TYPE="text/css" href="/includes/stylesheets/ebooks.css"></head><BODY TEXT="#000000" BGCOLOR="#FFFFFF"><CENTER><H1><img src="/publishers/que/series/professional/0789720221/button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>ANSI/ISO C++ Professional Programmer's Handbook</H1></CENTER><CENTER> <P><A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <HR></CENTER><H1 align="center">8</H1><h1 align="center"> Namespaces</h1><address>by Danny Kalev</address><ul> <li><a href="#Heading1">The Rationale Behind Namespaces</a> <li><a href="#Heading2">A Brief Historical Background</a> <ul> <li><a href="#Heading3">Large-Scale Projects Are More Susceptible to Name Clashes</a> </ul> <li><a href="#Heading4">Properties of Namespaces</a> <ul> <li><a href="#Heading5">Fully Qualified Names</a> <li><a href="#Heading6">A using Declaration and a using Directive</a> <li><a href="#Heading7">Namespaces Can Be Extended </a> <li><a href="#Heading8">Namespace Aliases</a> <li><a href="#Heading9">Koenig Lookup</a> <li><a href="#Heading10">Namespaces in Practice</a> </ul> <li><a href="#Heading11">Namespace Utilization Policy in Large-Scale Projects</a> <li><a href="#Heading12">Namespaces and Version Control</a> <ul> <li><a href="#Heading13">Namespaces Do not Incur Additional Overhead</a> </ul> <li><a href="#Heading14">The Interaction of Namespaces with Other Language Features</a> <ul> <li><a href="#Heading15">Scope Resolution Operator Should Not Be Used To Designate Global Names</a> <li><a href="#Heading16">Turning an External Function into A File-Local Function</a> <li><a href="#Heading17">Standard Headers Names</a> </ul> <li><a href="#Heading18">Restrictions on Namespaces</a> <ul> <li><a href="#Heading19">Namespace std Can Not Be Modified</a> <li><a href="#Heading20">User-Defined new and delete Cannot Be Declared in a Namespace</a> </ul> <li><a href="#Heading21">Conclusions</a> </ul><hr size=4><p>Namespaces were introduced to the C++ Standard in 1995. This chapter explains what namespaces are and why they were added to the language. You will see how namespaces can avoid name conflicts and how they facilitate configuration management and version control in large-scale projects. Finally, you will learn how namespaces interact with other language features.</p><h2> <a name="Heading1">The Rationale Behind Namespaces</a></h2><p>In order to understand why namespaces were added to the language in the first place, here's an analogy: Imagine that the file system on your computer did not have directories and subdirectories at all. All files would be stored in a flat repository, visible all the time to every user and application. Consequently, extreme difficulties would arise: Filenames would clash (with some systems limiting a filename to eight characters, plus three for the extension, this is even more likely to happen), and simple actions such as listing, copying, or searching files would be much more difficult. In addition, security and authorization restrictions would be severely compromised.</p><p>Namespaces in C++ are equivalent to directories. They can be nested easily, they protect your code from name conflicts, they enable you to hide declarations, and they do not incur any runtime or memory overhead. Most of the components of the C++ Standard Library are grouped under namespace <tt>std</tt>. Namespace <tt>std</tt> is subdivided into additional namespaces such as <tt>std::rel_ops</tt>, which contains the definitions of STL's overloaded operators.</p><h2> <a name="Heading2">A Brief Historical Background</a></h2><p>In the early 1990s, when C++ was gaining popularity as a general purpose programming language, many vendors were shipping proprietary implementations of various component classes. Class libraries for string manipulations, mathematical functions, and data containers were integral parts of frameworks such as MFC, STL, OWL, and others. The proliferation of reusable components caused a name-clashing problem. A class named <tt>vector</tt><i>, </i>for instance, might appear in a mathematical library and in another container library that were both used at the same time; or a class named <tt>string</tt> might be found in almost every framework and class library. It was impossible for the compiler to distinguish between different classes that had identical names. Similarly, linkers could not cope with identical names of member functions of classes with indistinguishable names. For example, a member function</p><pre><tt>vector::operator==(const vector&);</tt></pre><p>might be defined in two different classes -- the first might be a class of a mathematical library, whereas the other might belong to some container library.</p><h3> <a name="Heading3">Large-Scale Projects Are More Susceptible to Name Clashes</a></h3><p>Name-clashes are not confined to third party software libraries. In large-scale software projects, short and elegant names for classes, functions, and constants can also cause name conflicts because it is likely that the same name might be used more than once to indicate different entities by different developers. In the pre-namespace era, the only workaround was to use various affixes in identifiers' names. This practice, however, is tedious and error prone. Consider the following:</p><pre><tt>class string // short but dangerous. someone else may have picked //this name already...</tt><tt>{</tt><tt> //...</tt><tt>};</tt><tt>class excelSoftCompany_string // a long name is safer but tedious. //A nightmare if company changes its name...</tt><tt>{</tt><tt> //...</tt><tt>}; </tt></pre><p>Namespaces enable you to use convenient, short, and intelligible names safely. Instead of repeating the unwieldy affixes time after time, you can group your declarations in a namespace and factor out the recurring affix as follows:</p><pre><tt>//file excelSoftCompany.h</tt><tt>namespace excelSoftCompany { // a namespace definition</tt><tt> class string {/*..*/};</tt><tt> class vector {/*..*/};</tt><tt>}</tt></pre><p>Namespace members, like class members, can be defined separately from their declarations. For example</p><pre><tt>#include <iostream></tt><tt>using namespace std;</tt><tt>namespace A</tt><tt>{</tt><tt> void f(); //declaration</tt><tt>}</tt><tt>void A::f() //definition in a separate file</tt><tt>{</tt><tt> cout<<"in f"<<endl;</tt><tt>}</tt><tt>int main()</tt><tt>{</tt><tt> A::f();</tt><tt> return 0;</tt><tt>}</tt></pre><h2> <a name="Heading4">Properties of Namespaces</a></h2><p>Namespaces are more than just name containers. They were designed to allow fast and simple migration of legacy code without inflicting any overhead. Namespaces have several properties that facilitate their usage. The following sections discuss these properties.</p><h3> <a name="Heading5">Fully Qualified Names</a></h3><p>A namespace is a scope in which declarations and definitions are grouped together. In order to refer to any of these from another scope, a <i>fully qualified name</i> is required. A fully qualified name of an identifier consists of its namespaces, followed by a scope resolution operator (<tt>::</tt>), its class name, and, finally, the identifier itself. Because both namespaces and classes can be nested, the resulting name can be rather long -- but it ensures unique identification:</p><pre><tt>unsigned int maxPossibleLength =</tt><tt> std::string::npos; //a fully qualified name. npos is a member of string; //string belongs to namespace std</tt><tt> int *p = ::new int; //distinguish global new from overloaded new </tt></pre><p>However, repeating the fully qualified name is tedious and less readable. Instead, you can use a<i> using declaration</i> or a <i>using directive</i>.</p><h3> <a name="Heading6">A using Declaration and a using Directive</a></h3><p>A <tt>using</tt> declaration consists of the keyword <tt>using</tt>, followed by a <cite>namespace::member</cite>. It instructs the compiler to locate every occurrence of a certain identifier (type, operator, function, constant, and so on) in the specified namespace, as if the fully qualified name were supplied. For example</p><pre><tt>#include <vector> //STL vector; defined in namespace std</tt><tt>int main()</tt><tt>{</tt><tt> using std::vector; //using declaration; every occurrence of vector //is looked up in std</tt><tt> vector <int> vi; </tt><tt> return 0;</tt><tt>}</tt></pre><p>A <tt>using</tt> directive, on the other hand, renders all the names of a specified namespace accessible in the scope of the directive. It consists of the following sequence: <tt>using namespace</tt>, followed by a namespace name. For example</p><pre><tt>#include <vector> // belongs to namespace std</tt><tt>#include <iostream> //iostream classes and operators are also in namespace std</tt><tt>int main()</tt><tt>{</tt><tt> using namespace std; // a using-directive; all <iostream> and <vector> //declarations now accessible</tt><tt> vector <int> vi;</tt><tt> vi.push_back(10);</tt><tt> cout<<vi[0];</tt><tt> return 0;</tt><tt>}</tt></pre><p>Look back at the <tt>string</tt> class example (the code is repeated here for convenience):</p><pre><tt>//file excelSoftCompany.h</tt><tt>namespace excelSoftCompany </tt><tt>{ </tt><tt> class string {/*..*/};</tt><tt> class vector {/*..*/};</tt><tt>}</tt></pre><p>You can now access your own <tt>string</tt> class as well as the standard <tt>string</tt> class in the same program as follows:</p><pre><tt>#include <string> // std::string</tt><tt>#include "excelSoftCompany.h"</tt>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -