Effective C ++ 2e Item28

zhaozj2021-02-11  188

Terms 28: Divided Global Name Space

The biggest problem with global space is that it is only one. In large software projects, many people often put their definitions in this single space, which inevitably leads to name conflicts. For example, suppose Library1.h defines some constants, including:

const Double LIB_VERSION = 1.204;

Similarly, library2.h is also defined:

Const int lib_version = 3;

Obviously, if a program wants to contain library1.h and library2.h, there is a problem. For this type of problem, you have no other means in addition to the mouth, or send the author to retaliate mail, or to edit the header file to eliminate the name of the name.

However, as a programmer, you can try our best to write these issues to others. For example, some prefix that is not much likely to cause conflicts can be presumed, add each global symbol. Of course, it has to be acknowledged that such a combined identifier does not look so comfortable.

Another better way is to use C Namespace. Namespace is in essence, like a prefix method, but avoids others always see prefix. So don't do this:

Const Double SDMBOOK_VERSION = 2.0; // In this library, // Each symbol begins with "SDM" Class SDMHANDLE {...};

SDMHANDLE & SDMGETHANDLE (); // Why is the function to declare this? // See Terms 47

And do this:

Namespace SDM {const Double book_version = 2.0; class handle {...}; handle & getHandle ();}

Users can then access symbols in this name space through three ways: introduce all symbols in the namespace to a certain user space; introduce some symbols into a certain user space; or once via the modifier Sex use a symbol:

Void f1 () {using namespace SDM; // allows all symbols in the SDM to use // modifier

Cout << book_version; // Explain to SDM :: Book_Version ...

Handle h = getHandle (); // handle Explains to SDM :: Handle, // GetHandle Interpretation as SDM :: GetHandle ...

}

Void f2 () {using sdm :: book_version; // makes only Book_Version can be used without adding // modifier

Cout << Book_version; // Explain to // SDM :: Book_Version ...

Handle h = getHandle (); // error! Handle and getHandle // have not introduced to this space ...

}

Void f3 () {cout << SDM :: Book_version; // Make Book_Version // That is active in this statement ...

Double D = Book_version; // Error! Book_version // is not in this space

Handle h = getHandle (); // error! Handle and getHandle // have not introduced to this space ...

}

(Some namespace has no name. This unnamed name space is generally used to limit the visibility of the internal elements of the namespace. See the Terms M31.)

One of the biggest benefits brought by name spaces is that potential second meaning will not cause errors (see Terms 26). So, introducing the same symbol name from multiple different namespaces that will not cause conflicts (if you really never use this symbol). For example, in addition to the namespace SDM, if you want to use the name space below:

Namespace acmewindowsystem {

...

Typedef int handle;

...

}

There is no conflict with SDM and AcmeWindowsystem when not citing symbol Handle. If you really want to reference, you can clearly indicate which name space of the Handle:

Void f () {using namespace SDM; // Introduced all symbols in the SDM Using Namespace AcmeWindowsystem; // Introduced all symbols in ACME

... // Free reference SDM / / and other symbols from Handle //

Handle H; / / Error! Which handle?

SDM :: Handle H1; / / correct, no second

Acmewindowsystem :: Handle H2; // Nothing

...

}

If you use a conventional header-based method, just simply contain SDM.H and Acme.h, in which compilation will not pass because there is a plurality of definitions of Handle.

The concept of name space is relatively late, so some people will think it is not important, but there is no. But this idea is wrong because almost all things in the C standard library (see Terms 49) are exist in the namespace STD. This may make you don't agree, but it affects you in a direct way: this is why C provides a header file that looks very interesting, no extension, such as , , etc. See Terms 49 in detail.

Some compilers may not support because the concept of name space is relatively late. Even if this is, then there is no reason to pollute the global name space, because you can use Struct to approximate Namespace. You can do this: first create a structure to save the global symbol name, then put these global symbols as static members into the structure:

// Definition of a structure for simulating the namespace Struct SDM {Static const Double book_version; class handle {...}; static handle & getHandle ();}; const double sdm :: book_version = 2.0; // static member definition

Now, if someone wants to access these global symbol names, only simply add the structure name as a prefix:

Void f () {cout << SDM :: Book_Version;

...

SDM :: Handle H = SDM :: getHandle ();

...}

However, if there is no name conflict in the global scope, users will feel that they have more troublesome. Fortunately, there is a way to let users choose to use them or ignore them.

For type names, you can explicitly remove spatial references with type definitions (TypeDef). For example, assume that there is a type name t in the structural S (the simulated namespace), which can be used to make T be a synonym of S :: t as synonym:

Typedef SDM :: Handle Handle;

For each (static) object X in the structure, one (global) can be provided to reference X, and initialize to s :: x:

Const Double & Book_Version = SDM :: Book_Version;

Honestly, if you read the terms 47, you will not like to define a non-local static object like Book_Version. (You will replace such objects with the functions introduced in Terms 47)

The method of processing the function is the same, but to note that even if the definition of the reference is legal, the maintainer of the code will prefer you use the function pointer:

SDM :: Handle & (* const grandle) () = // getHandle is the Const pointer to SDM :: GetHandle SDM :: GetHandle; // (see Terms 21)

Note that getHandle is a normally pointer. Because you certainly don't want your user to point it to something, not SDM :: getHandle, right?

(If you really want to know how to define a reference to a function, see below:

SDM :: Handle & (& GetHandle) () = // GetHandle is a reference to SDM :: GetHandle; // SDM :: GetHandle

I personally think that this is also very good, but you may have never seen it before. In addition to initialization, the reference to the function is identical to the function of the function of the function, but the function pointer is easier to understand. )

With the type definitions and references above, users who do not encounter global name conflicts will use the type and object name of the modifier; their, the user who has a global name conflict will ignore the definition of the type and reference, Take the symbolic name of the trigger. Also note that all users want to use this book name, so put the type definition and reference in a separate header file, do not mix it and (analog Namespace) structure.

Struct is a good approximate, but actually differs far from Namespace. It is very lacking in many ways, which is obvious that the handling of the operator. If the operator is defined as a static member of the structure, it can only be used by the function call, and can be used to use natural infix syntax as designed by the regular operator: // Define an analog name space The structure, the structure inside the structure contains Widgets type // and functions. Widgets object supports Operator for additional operations Struct widgets {class widget {...};

// Refer to Terms 21: Why return const static const widget Operator (Const Widget & LHS, Const Widget & RHS);

...

}

/ / Establish a global (no modifier) ​​name for the WIDGE and Operator // described above

Typedef widgets :: widget widget;

Const Widget (* const portrator ) (const widget &, //); // Operator cannot be a pointer

Widget W1, W2, SUM

SUM = W1 W2; // Error! This space has no declaration // parameter is Widget's Operator

SUM = Widgets :: Operator (W1, W2); // Legal, but not // "Nature" grammar

Because of these restrictions, once the compiler supports, use the real namespace as soon as possible.

转载请注明原文地址:https://www.9cbs.com/read-4450.html

New Post(0)