📄 ch08.htm
字号:
other referring to a satellite connection -- can have an identical name: <tt>Connection.</tt> If, however, communication software components and database access objects are declared in two distinct namespaces, the potential of name clashes is minimized. Therefore, <tt>com::Connection</tt> and <tt>dba::Connection</tt> can be used in the same application simultaneously. A systematic approach can be based on allocating a separate namespace for every team in a project in which all the components are declared. Such a policy can help you avoid name clashes among different teams and third party code used in the project.</p><h2> <a name="Heading12">Namespaces and Version Control</a></h2><p>Successful software projects do not end with the product's rollout. In most projects, new versions that are based on their predecessors are periodically released. Moreover, previous versions have to be supported, patched, and adjusted to operate with new operating systems, locales, and hardware. Web browsers, commercial databases, word processors, and multimedia tools are examples of such products. It is often the case that the same development team has to support several versions of the same software product. A considerable amount of software can be shared among different versions of the same product, but each version also has its specific components. Namespace aliases can be used in these cases to switch swiftly from one version to another.</p><p>Continuous projects in general have a pool of infrastructure software components that are used ubiquitously. In addition, every version has its private pool of specialized components. Namespace aliases can provide <i>dynamic namespaces</i>; that is, a namespace alias can point at a given time to a namespace of version X and, at another time, it can refer to a different namespace. For example</p><pre><tt>namespace ver_3_11 //16 bit</tt><tt>{ </tt><tt> class Winsock{/*..*/};</tt><tt> class FileSystem{/*..*/};</tt><tt>};</tt><tt>namespace ver_95 //32 bit</tt><tt>{ </tt><tt> class Winsock{/*..*/};</tt><tt> class FileSystem{/*..*/};</tt><tt>}</tt><tt>int main()//implementing 16 bit release</tt><tt>{ </tt><tt> namespace current = ver_3_11; // current is an alias of ver_3_11</tt><tt> using current::Winsock;</tt><tt> using current::FileSystem;</tt><tt> FileSystem fs; // ver_3_11::FileSystem</tt><tt> //...</tt><tt> return 0;</tt><tt>}</tt></pre><p>In this example, the alias <tt>current</tt> is a symbol that can refer to either <tt>ver_3_11</tt> or <tt>ver_95</tt>. To switch to a different version, the programmer only has to assign a different namespace to it.</p><h3> <a name="Heading13">Namespaces Do not Incur Additional Overhead</a></h3><p>Namespace resolution, including Koenig lookup, are statically resolved. The underlying implementation of namespaces occurs by means of <i>name mangling,</i> whereby the compiler incorporates the function name with its list of arguments, its class name, and its namespace in order to create a unique name for it (see Chapter 13, "C Language Compatibility Issues," for a detailed account of name mangling). Therefore, namespaces do not incur any runtime or memory overhead.</p><h2> <a name="Heading14">The Interaction of Namespaces with Other Language Features</a></h2><p>Namespaces interact with other features of the language and affect programming techniques. Namespaces made some features in C++ superfluous or undesirable.</p><h3> <a name="Heading15">Scope Resolution Operator Should Not Be Used To Designate Global Names</a></h3><p>In some frameworks (MFC, for instance), it is customary to add the scope resolution operator, <tt>::</tt>, before a global function's name to mark it explicitly as a function that is not a class member (as in the following example):</p><pre><tt>void String::operator = (const String& other)</tt><tt>{</tt><tt> ::strcpy (this->buffer, other.getBuff()); </tt><tt>}</tt></pre><p>This practice is not recommended. Many of the standard functions that were once global are now grouped inside namespaces. For example, <tt>strcpy</tt> now belongs to namespace <tt>std</tt>, as do most of the Standard Library's functions. Preceding these functions with the scope resolution operator might confuse the lookup algorithm of the compiler; furthermore, doing so undermines the very idea of partitioning the global namespace. Therefore, it is recommended that you leave the scope resolution operator off the function's name.</p><h3> <a name="Heading16">Turning an External Function into A File-Local Function</a></h3><p>In standard C, a nonlocal identifier that is declared to be static has <i>internal linkage</i>, which means that it is accessible only from within the translation unit (source file) in which it is declared (see also Chapter 2, "Standard Briefing: The Latest Addenda to ANSI/ISO C++"). This technique is used to support information hiding (as in the following example):</p><pre><tt> //File hidden.c</tt><tt>static void decipher(FILE *f); // accessible only from within this file</tt><tt> // now use this function in the current source file</tt><tt>decipher ("passwords.bin");</tt><tt> //end of file</tt></pre><p>Although it is still supported in C++, this convention is now considered a <i>deprecated feature. </i>Future releases of your compiler might issue a warning message when they find a static identifier that is not a member of a class. In order to make a function accessible only from within its translation unit, use an <i>unnamed namespace </i>instead. The following example demonstrates the process:</p><pre><tt>//File hidden.cpp</tt><tt>namespace //unnamed</tt><tt>{</tt><tt> void decipher(FILE *f); // accessible only from within this file</tt><tt>}</tt><tt> //now use the function in the current source file. </tt><tt> //No using declarations or directives are needed</tt><tt>decipher ("passwords.bin");</tt></pre><p>Although names in an unnamed namespace might have external linkage, they can never be seen from any other translation unit; the net effect of this is that the names of an unnamed namespace appear to have static linkage. If you declare another function with the same name in an unnamed namespace of another file, the two functions are hidden from one another, and their names do not clash.</p><h3> <a name="Heading17">Standard Headers Names</a></h3><p>All Standard C++ header files now have to be included as follows:</p><pre><tt>#include <iostream> //note: no ".h" extension</tt></pre><p>That is, the .h extension is omitted. Standard C header files also obey this convention, with the addition of the letter <i>c</i> to their name. Therefore, a C standard header that was formerly named <tt><xxx.h></tt> is now <tt><cxxx></tt>. For example</p><pre><tt>#include <cassert> //formerly: <assert.h> note the prefix 'c' and the //omission of ".h"</tt></pre><p>The older convention for C headers, <tt><xxx.h></tt>, is still supported; however, it is now considered deprecated and, therefore, is not to not be used in new C++ code. The reason for this is that C <tt><xxx.h></tt> headers inject their declarations into the global namespace. In C++, however, most standard declarations are grouped under namespace <tt>std</tt>,<i> </i>as are the <tt><cxxx></tt> Standard C headers. No inference is to be drawn from the actual name convention that is used on the physical location of a header file or its underlying name. In fact, most implementations share a single physical file for the <tt><xxx.h></tt> and its corresponding <tt><cxxx></tt> notation. This is feasible due to some under-the-hood preprocessor tricks. Recall that you need to have a<i> </i><tt>using</tt> declaration, a<i> </i><tt>using</tt> directive, or a fully qualified name in order to access the declarations in the new style standard headers. For example</p><pre><tt>#include <cstdio></tt><tt>using namespace std; </tt><tt>void f()</tt><tt>{</tt><tt> printf ("Hello World\n");</tt><tt>}</tt></pre><h2> <a name="Heading18">Restrictions on Namespaces</a></h2><p>The C++ Standard defines several restrictions on the use of namespaces. These restrictions are meant to avert anomalies or ambiguities that can create havoc in the language.</p><h3> <a name="Heading19">Namespace std Can Not Be Modified</a></h3><p>Generally, namespaces are open, so it is perfectly legal to expand existing namespaces with additional declarations and definitions across several files. The only exception to the rule is namespace <tt>std</tt>. According to the Standard, the result of modifying namespace <tt>std</tt> with additional declarations -- let alone the removal of existing ones -- yields undefined behavior, and is to be avoided. This restriction might seem arbitrary, but it's just common sense -- any attempt to tamper with namespace <tt>std</tt> undermines the very concept of a namespace dedicated exclusively to standard declarations.</p><h3> <a name="Heading20">User-Defined new and delete Cannot Be Declared in a Namespace</a></h3><p>The Standard prohibits declarations of <tt>new</tt> and <tt>delete</tt> operators in a namespace. To see why, consider the following example:</p><pre><tt>char *pc; //global</tt><tt>namespace A</tt><tt>{</tt><tt> void* operator new ( std::size_t );</tt><tt> void operator delete ( void * );</tt><tt> void func ()</tt><tt> {</tt><tt> pc = new char ( 'a'); //using A::new</tt><tt> }</tt><tt>} //A</tt><tt>void f() { delete pc; } // call A::delete or //::delete?</tt></pre><p>Some programmers might expect the operator <tt>A::delete</tt> to be selected because it matches the operator <tt>new</tt> that was used to allocate the storage; others might expect the standard operator <tt>delete</tt> to be called because <tt>A::delete</tt> is not visible in function <tt>f()</tt>. By prohibiting declarations of <tt>new</tt> and <tt>delete</tt> in a namespace altogether, C++ avoids any such ambiguities.</p><h2> <a name="Heading21">Conclusions</a></h2><p>Namespaces were the latest addition to the C++ Standard. Therefore, some compilers do not yet support this feature. However, all compiler vendors will incorporate namespace support in the near future. The importance of namespaces cannot be over-emphasized. As you have seen, any nontrivial C++ program utilizes components of the Standard Template Library, the <tt>iostream</tt> library, and other standard header files -- all of which are now namespace <tt>members</tt>.</p><p>Large-scale software projects can use namespaces cleverly to avoid common pitfalls and to facilitate version control, as you have seen.</p><p>C++ offers three methods for injecting a namespace constituent into the current scope. The first is a <tt>using</tt> directive, which renders all the members of a namespace visible in the current scope. The second is a <tt>using</tt> declaration, which is more selective and enables the injection of a single component from a namespace. Finally, a fully qualified name uniquely identifies a namespace member. In addition, the argument-dependent lookup, or Koenig lookup, captures the programmer's intention without forcing him or her to use wearying references to a namespace.</p><p> </p><CENTER><P><HR> <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> <BR><BR><BR><p></P><P>© <A HREF="/publishers/que/series/professional/0789720221/copy.htm">Copyright 1999</A>, Macmillan Computer Publishing. Allrights reserved.</p></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -