📄 ch08.htm
字号:
<tt>int main()</tt><tt>{</tt><tt> using namespace excelSoftCompany;</tt><tt> string s; //referring to class excelSoftCompany::string</tt><tt> std::string standardstr; //now instantiate an ANSI string</tt><tt> return 0;</tt><tt>}</tt></pre><h3> <a name="Heading7">Namespaces Can Be Extended </a></h3><p>The C++ standardization committee was well aware of the fact that related declarations can span across several translation units. Therefore, a namespace can be defined in parts. For example</p><pre><tt> //file proj_const.h</tt><tt>namespace MyProj </tt><tt>{</tt><tt> enum NetProtocols</tt><tt> {</tt><tt> TCP_IP,</tt><tt> HTTP,</tt><tt> UDP</tt><tt> }; // enum</tt><tt>}</tt><tt> //file proj_classes.h</tt><tt>namespace MyProj</tt><tt>{ // extending MyProj namespace</tt><tt> class RealTimeEncoder{ public: NetProtocols detect(); };</tt><tt> class NetworkLink {}; //global</tt><tt> class UserInterface {};</tt><tt>}</tt></pre><p>In a separate file, the same namespace can be extended with additional declarations.</p><p>The complete namespace <tt>MyProj</tt> can be extracted from both files as follows:</p><pre><tt> //file app.cpp</tt><tt>#include "proj_const.h"</tt><tt>#include "proj_classes.h"</tt><tt>int main() </tt><tt>{</tt><tt> using namespace MyProj;</tt><tt> RealTimeEncoder encoder;</tt><tt> NetProtocols protocol = encoder.detect();</tt><tt> return 0;</tt><tt>} </tt></pre><h3> <a name="Heading8">Namespace Aliases</a></h3><p>As you have observed, choosing a short name for a namespace can eventually lead to a name clash. However, very long namespaces are not easy to use. For this purpose,<i> </i>a <i>namespace alias</i> can be used. The following example defines the alias <tt>ESC</tt> for the unwieldy <tt>Excel_Software_Company</tt> namespace. Namespace aliases have other useful purposes, as you will see soon.</p><pre><tt>//file decl.h</tt><tt>namespace Excel_Software_Company </tt><tt>{</tt><tt> class Date {/*..*/};</tt><tt> class Time {/*..*/};</tt><tt>}</tt><tt>//file calendar.cpp</tt><tt>#include "decl.h"</tt><tt>int main()</tt><tt>{</tt><tt> namespace ESC = Excel_Software_Company; //ESC is an alias for </tt><tt> // Excel_Software_Company</tt><tt> ESC::Date date;</tt><tt> ESC::Time time;</tt><tt> return 0;</tt><tt>}</tt></pre><h3> <a name="Heading9">Koenig Lookup</a></h3><p>Andrew Koenig, one of the creators of C++, devised an algorithm for resolving namespace members' lookup. This algorithm, also called <i>argument dependent lookup</i>, is used in all standard-compliant compilers to handle cases such as the following:</p><blockquote> <hr> <strong>CAUTION: </strong> Please note that some existing compilers do not yet fully support Koenig lookup. Consequently, the following programs -- which rely on Koenig lookup -- might not compile under compilers that are not fully compliant to the ANSI/ISO standard in this respect. <hr></blockquote><pre><tt>namespace MINE</tt><tt>{</tt><tt> class C {};</tt><tt> void func;</tt><tt>}</tt><tt>MINE::C c; // global object of type MINE::C</tt><tt>int main()</tt><tt>{</tt><tt> func( c ); // OK, MINE::f called</tt><tt> return 0;</tt><tt>}</tt></pre><p>Neither a <tt>using</tt> declaration nor a <tt>using</tt> directive exists in the program. Still, the compiler did the right thing -- it correctly identified the unqualified name <tt>func</tt> as the function declared in namespace <tt>MINE</tt> by applying Koenig lookup. </p><p>Koenig lookup instructs the compiler to look not just at the usual places, such as the local scope, but also at the namespace that contains the argument's type. Therefore, in the following source line, the compiler detects that the object <tt>c</tt>, which is the argument of the function <tt>func()</tt>, belongs to namespace <tt>MINE</tt>. Consequently, the compiler looks at namespace <tt>MINE</tt> to locate the declaration of <tt>func()</tt>, "guessing" the programmer's intent:</p><pre><tt>func( c ); // OK, MINE::f called</tt></pre><p>Without Koenig lookup, namespaces impose an unacceptable tedium on the programmer, who has to either repeatedly specify the fully qualified names or use numerous <tt>using</tt> declarations. To push the argument in favor of Koenig lookup even further, consider the following example:</p><pre><tt>#include<iostream></tt><tt>using std::cout;</tt><tt>int main()</tt><tt>{</tt><tt> cout<<"hello"; //OK, operator << is brought into scope by Koenig lookup</tt><tt> return 0;</tt><tt>}</tt></pre><p>The <tt>using</tt> declaration injects <tt>std::cout</tt> into the scope of <tt>main()</tt>, thereby enabling the programmer to use the nonqualified name <tt>cout</tt>. However, the overloaded <tt><<</tt> operator, as you might recall, is not a member of <tt>std::cout</tt>. It is a friend function that is defined in namespace <tt>std</tt>, and which takes a <tt>std::ostream</tt> object as its argument. Without Koenig lookup, the programmer has to write something similar to the following:</p><pre><tt>std::operator<<(cout, "hello");</tt></pre><p>Alternatively, the programmer can provide a <tt>using namespace std;</tt> directive. None of these options are desirable, however, because they clutter up code and can become a source of confusion and errors. (<tt>using</tt> directives are the least favorable form for rendering names visible in the current scope because they make all the members of a namespace visible indiscriminately). Fortunately, Koenig lookup "does the right thing" and saves you from this tedium in an elegant way.</p><p>Koenig lookup is applied automatically. No special directives or configuration switches are required to activate it, nor is there any way to turn it off. This fact has to be kept in mind because it can have surprising results in some circumstances. For example</p><pre><tt>namespace NS1</tt><tt>{</tt><tt> class B{};</tt><tt> void f;</tt><tt>};</tt><tt>void f(NS1::B); </tt><tt>int main()</tt><tt>{</tt><tt> NS1::B b;</tt><tt> f; // ambiguous; NS1::f() or f(NS1::B)?</tt><tt> return 0;</tt><tt>}</tt></pre><p>A Standard-compliant compiler should issue an error on ambiguity between <tt>NS1::f(NS1::B)</tt> and <tt>f(NS1::B)</tt>. However, noncompliant compilers do not complain about the ambiguous call; they simply pick one of the versions of <tt>f()</tt>. This, however, might not be the version that the programmer intended. Furthermore, the problem might arise only at a later stage of the development, when additional versions of <tt>f()</tt> are added to the project -- which can stymie the compiler's lookup algorithm. This ambiguity is not confined to global names. It might also appear when two namespaces relate to one another -- for instance, if a namespace declares classes that are used as parameters of a class member function that is declared in a different namespace.</p><h3> <a name="Heading10">Namespaces in Practice</a></h3><p>The conclusion that can be drawn from the previous examples is that namespaces, like other language features, must be used judiciously. For small programs that contain only a handful of classes and a few source files, namespaces are not necessary. In most cases, such programs are coded and maintained by a single programmer, and they use a limited number of components. The likelihood of name clashes in this case is rather small. If name clashes still occur, it is always possible to rename the existing classes and functions, or simply to add namespace later.</p><p>On the other hand, large-scale projects -- as was stated previously -- are more susceptible to name clashes; therefore, they need to use namespaces systematically. It is not unusual to find projects on which hundreds of programmers on a dozen or so development teams are working together. The development of Microsoft Visual C++ 6.0, for example, lasted 18 months, and more than 1000 people were involved in the development process. Managing such a huge project requires well documented coding policies -- and namespaces are one of the tools in the arsenal.</p><h2> <a name="Heading11">Namespace Utilization Policy in Large-Scale Projects</a></h2><p>To see how namespaces can be used in configuration management, imagine an online transaction processing system of an imaginary international credit card company, Unicard. The project comprises several development teams. One of them, the database administration team, is responsible for the creation and maintenance of the database tables, indexes, and access authorizations. The database team also has to provide the access routines and data objects that retrieve and manipulate the data in the database. A second team is responsible for the graphical user interface. A third team deals with the international online requests that are initiated by the cinemas, restaurants, shops, and so on where tourists pay with their international Unicard. Every purchase of a cinema ticket, piece of jewelry, or art book has to be confirmed by Unicard before the card owner is charged. The confirmation process involves checking for the validity of the card, its expiration date, and the card owner's balance. A similar confirmation procedure is required for domestic purchases. However, international confirmation requests are transmitted via satellite, whereas domestic confirmations are usually done on the telephone. </p><p>In software projects, code reuse is paramount. Because the same business logic is used for both domestic and international confirmations, the same database access objects need to be used to retrieve the relevant information and perform the necessary computations. Still, an international confirmation also involves a sophisticated communication stack that receives the request that is transmitted via satellite, decrypts it, and returns an encrypted response to the sender. A typical implementation of satellite-based confirmation application can be achieved by means of combining the database access objects with the necessary communication objects that encapsulate protocols, communication layers, priority management, message queuing, encryption, and decryption. It is not difficult to imagine a name conflict resulting from the simultaneous use of the communication components and the database access objects. </p><p>For example, two objects -- one encapsulating a database connection and the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -