Tải bản đầy đủ (.pdf) (10 trang)

Absolute C++ (4th Edition) part 48 docx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (148.07 KB, 10 trang )

Namespaces 477
Note that you can have any number of these namespace groupings for a single
namespace. In Display 11.5, we used two namespace groupings for namespace
Space1
and two other groupings for namespace Space2.
Every name defined in a namespace is available inside the namespace groupings, but
the names can also be made available to code outside the namespace groupings. For
example, the function declaration and function definition in the namespace
Space1 can
be made available with the
using directive
using namespace Space1
as illustrated in Display 11.5.
Display 11.5 Namespace Demonstration
(part 2 of 2)
26
27 namespace Space1
28 {
29 void greeting( )
30 {
31 cout << "Hello from namespace Space1.\n";
32 }
33 }
34 namespace Space2
35 {
36 void greeting( )
37 {
38 cout << "Greetings from namespace Space2.\n";
39 }
40 }
41 void bigGreeting( )


42 {
43 cout << "A Big Global Hello!\n";
44 }
S
AMPLE
D
IALOGUE
Greetings from namespace Space2.
Hello from namespace Space1.
A Big Global Hello!
478 Separate Compilation and Namespaces
Self-Test Exercises
6. Consider the program shown in Display 11.5. Could we use the name greeting in place
of
bigGreeting?
7. In Exercise 6, we saw that you could not add a definition for the following function to the
global namespace:
void greeting( );
Can you add a definition for the following function declaration to the global namespace?
void greeting(int howMany );

USING DECLARATIONS
This subsection describes a way to qualify a single name so that you can make only one
name from a namespace available to your program, rather than making all the names in
a namespace available. We saw this technique in Chapter 1 and so this is a review and
amplification of what we said in Chapter 1.
Suppose you are faced with the following situation. You have two namespaces,
NS1
and NS2. You want to use the function fun1 defined in NS1 and the function fun2
defined in namespace NS2. The complication is that both NS1 and NS2 also define a

function
myFunction. (Assume all functions in this discussion take no arguments, so
overloading does not apply.) There is a problem with
using namespace NS1;
using namespace NS2;
P
UTTING

A
D
EFINITION

IN

A
N
AMESPACE
You place a name definition in a namespace by placing it in a
namespace grouping
, which has
the following syntax:
namespace
Namespace_Name
{

Definition_1

Definition_2
.
.

.

Definition_Last
}
You can have multiple namespace groupings (even in multiple files), and all the definitions in all
the groupings will be in the same namespace.
Namespaces 479
This would potentially provide conflicting definitions for myFunction. (If the name
myFunction is never used, then most compilers will not detect the problem and will
allow your program to compile and run.)
What you need is a way to say you are using
fun1 in namespace NS1 and fun2 in
namespace
NS2 and nothing else in the namespaces NS1 and NS2. We have already been
using a technique that can handle this situation. The following is your solution:
using NS1::fun1;
using NS2::fun2;
A qualification of the form
using
Name_Space
::
One_Name
;
makes the (definition of the) name
One_Name
from the namespace
Name_Space
available, but
does not make any other names in
Name_Space

available. This is called a using declaration.
Note that the scope resolution operator
:: that we use in these using declarations is
the same as the scope resolution operator we use when defining member functions.
These two uses of the scope resolution operator have a similarity. For example, Display
11.2 had the following function definition:
void DigitalTime::advance(int hoursAdded, int minutesAdded)
{
hour = (hour + hoursAdded)%24;
advance(minutesAdded);
}
In this case the :: means that we are defining the function advance for the class Digi-
talTime
, as opposed to any other function named advance in any other class. Similarly,
using NS1::fun1;
means we are using the function named fun1 as defined in the namespace NS1, as
opposed to any other definition of
fun1 in any other namespace.
There are two differences between a
using
declaration, such as
using std::cout;
and a
using
directive such as
using namespace std;
The differences are:
1. A a
using declaration makes only one name in the namespace available to your
code, while a

using directive makes all the names in a namespace available.
2. A
using declaration introduces a name (like cout) into your code so no other use of
the name can be made. However, a
using directive only potentially introduces the
names in the namespace.
using
NS1::fun1;
using
declaration
480 Separate Compilation and Namespaces
Point 1 is pretty obvious. Point 2 has some subtleties. For example, suppose the
namespaces
NS1 and NS2 both provide definitions for myFunction, but have no other
name conflicts, then the following will produce no problems:
using namespace NS1;
using namespace NS2;
provided that (within the scope of these directives) the conflicting name myFunction is
never used in your code.
On the other hand, the following is illegal, even if the function
myFunction is never used:
using NS1::myFunction;
using NS2::myFunction;
Sometimes this subtle point can be important, but it does not impinge on most rou-
tine code. So, we will often use the term
using directive loosely to mean either a using
directive or a using declaration.

QUALIFYING NAMES
This section introduces a way to qualify names that we have not discussed before. Suppose

that you intend to use the name
fun1 as defined in the namespace NS1, but you only
intend to use it one time (or a small number of times). You can name the function (or
other item) using the name of the namespace and the scope resolution operator as follows:
NS1::fun1( );
This form is often used when specifying a parameter type. For example, consider
int getInput(std::istream inputStream)
. . .
In the function getInput, the parameter inputStream is of type istream, where
istream is defined as in the std namespace. If this use of the type name istream is the
only name you need from the
std namespace (or if all the names you need are similarly
qualified with
std::), then you do not need
using namespace std;
or
using std::istream;
Note that you can use std::istream even within the scope of a using directive for
another namespace which also defines the name
istream. In this case std::istream
and istream will have different definitions. For example, consider
using namespace MySpace;
void someFunction(istream p1, std::istream p2);
using
directive
Namespaces 481
Self-Test Exercises
Assuming istream is a type defined in the namespace MySpace, then p1 will have the
type
istream as defined in MySpace and p2 will have the type istream as defined in the

std namespace.
8. What is the output produced by the following program?
#include <iostream>
using namespace std;
namespace Hello
{
void message( );
}
namespace GoodBye
{
void message( );
}
void message( );
int main( )
{
using GoodBye::message;
{
using Hello::message;
message( );
GoodBye::message( );
}
message( );
return 0;
}
void message( )
{
cout << "Global message.\n";
}
namespace Hello
{

void message( )
{
482 Separate Compilation and Namespaces
Tip
Example
cout << "Hello.\n";
}
}
namespace GoodBye
{
void message( )
{
cout << "Good-Bye.\n";
}
}
9. Write the declaration (prototype) for a void function named wow. The function wow has
two parameters, the first of type
speed as defined in the speedway namespace and the sec-
ond of type
speed as defined in the indy500 namespace.
A C
LASS
D
EFINITION

IN

A
N
AMESPACE

In Displays 11.6 and 11.7 we have again rewritten both the header file dtime.h for the class Digi-
talTime
and the implementation file for the class DigitalTime. This time (no pun intended),
we have placed the definition in a namespace called
DTimeSavitch. Note that the namespace
DTimeSavitch spans the two files dtime.h and dtime.cpp. A namespace can span multiple
files.
If you rewrite the definition of the class DigitalTime as shown in Displays 11.6 and 11.7, then the
application file in Display 11.3 needs to specify the namespace
DTimeSavitch in some way, such
as the following:
using namespace DTimeSavitch;
or
using DTimeSavitch::DigitalTime;
C
HOOSING

A
N
AME

FOR

A
N
AMESPACE
It is a good idea to include your last name or some other unique string in the names of your
namespaces so as to reduce the chance that somebody else will use the same namespace name
as you do. With multiple programmers writing code for the same project, it is important that
namespaces that are meant to be distinct really do have distinct names. Otherwise, you can easily

have multiple definitions of the same names in the same scope. That is why we included the name
Savitch in the namespace DtimeSavitch in Display 11.9.
Namespaces 483
Display 11.6 Placing a Class in a Namespace (Header File)
1 //This is the header file dtime.h.
2 #ifndef DTIME_H
3 #define DTIME_H
4 #include <iostream>
5 using std::istream;
6 using std::ostream;
7 namespace DTimeSavitch
8 {
9
10 class DigitalTime
11 {
12
13
<
The definition of the class DigitalTime is the same as in Display 11.1.
>
14 };
15
16 }// DTimeSavitch
17 #endif //DTIME_H
A better version of this class definition will be
given in Displays 11.8 and 11.9.
Note that the namespace
DTimeSavitch spans two
files. The other is shown in Display 11.7.
Display 11.7 Placing a Class in a Namespace (Implementation File)

1 //This is the implementation file dtime.cpp.
2 #include <iostream>
3 #include <cctype>
4 #include <cstdlib>
5 using std::istream;
6 using std::ostream;
7 using std::cout;
8 using std::cin;
9 #include "dtime.h"
10 namespace DTimeSavitch
11 {
12
13
<All the function definitions from Display 11.2 go here.>
14
15 }// DTimeSavitch
You can use the single using directive
using namespace std;
in place of these four using declarations.
However, the four
using declarations are a
preferable style.
484 Separate Compilation and Namespaces

UNNAMED NAMESPACES
A compilation unit is a file, such as a class implementation file, along with all the files
that are
#included in the file, such as the interface header file for the class. Every com-
pilation unit has an unnamed namespace. A namespace grouping for the unnamed
namespace is written in the same way as for any other namespace, but no name is

given, as in the following example:
namespace
{
void sampleFunction( )
.
.
.
} //unnamed namespace
All the names defined in the unnamed namespace are local to the compilation unit,
and so the names can be reused for something else outside the compilation unit. For
example, Displays 11.8 and 11.9 show a rewritten (and final) version of the interface
compilation
unit
Display 11.8 Hiding the Helping Functions in a Namespace (Interface File)
(part 1 of 2)
1 //This is the header file dtime.h. This is the interface for the class DigitalTime.
2 //Values of this type are times of day. The values are input and output in 24-hour
3 //notation, as in 9:30 for 9:30 AM and 14:45 for 2:45 PM.
4 #ifndef DTIME_H
5 #define DTIME_H
6 #include <iostream>
7 using std::istream;
8 using std::ostream;
9 namespace DTimeSavitch
10 {
11 class DigitalTime
12 {
13 public:
14 DigitalTime(int theHour, int theMinute);
15 DigitalTime( );

16 //Initializes the time value to 0:00 (which is midnight).
17 getHour( ) const;
18 getMinute( ) const;
19 void advance(int minutesAdded);
20 //Changes the time to minutesAdded minutes later.
This is our final version of the class DigitalTime.
This is the best version and the one you should use.
The implementation to use with this interface is
given in Display 11.9.
Namespaces 485
Display 11.8 Hiding the Helping Functions in a Namespace (Interface File)
(part 2 of 2)
21 void advance(int hoursAdded, int minutesAdded);
22 //Changes the time to hoursAdded hours plus minutesAdded minutes later.
23 friend bool operator
==(const DigitalTime& time1,
24 const DigitalTime& time2);
25 friend istream& operator >>(istream& ins, DigitalTime& theObject);
26 friend ostream& operator <<(ostream& outs,
27 const DigitalTime& theObject);
28 private:
29 int hour;
30 int minute;
31 };
32 } //DTimeSavitch
33 #endif //DTIME_H
Note that the helping functions are not
mentioned in the interface file.
Display 11.9 Hiding the Helping Functions in a Namespace (Implementation File)
(part 1 of 3)

1 //This is the implementation file dtime.cpp of the class DigitalTime.
2 //The interface for the class DigitalTime is in the header file dtime.h.
3 #include <iostream>
4 #include <cctype>
5 #include <cstdlib>
6 using std::istream;
7 using std::ostream;
8 using std::cout;
9 using std::cin;
10 #include "dtime.h"
11 namespace
12 {
13 int digitToInt(char c)
14 {
15 return ( int(c) - int(’0’) );
16 }
17 //Uses iostream, cctype, and cstdlib:
18 void readMinute(int& theMinute)
19 {
20 char c1, c2;
21 cin >> c1 >> c2;
22 if (!(isdigit(c1) && isdigit(c2)))
23 {
24 cout << "Error: illegal input to readMinute\n";
Specifies the unnamed namespace
Names defined in the unnamed namespace are
local to the compilation unit. So, these helping
functions are local to the file
dtime.cpp.
486 Separate Compilation and Namespaces

Display 11.9 Hiding the Helping Functions in a Namespace (Implementation File)
(part 2 of 3)
25 exit(1);
26 }
27 theMinute = digitToInt(c1)*10 + digitToInt(c2);
28 if (theMinute < 0 || theMinute > 59)
29 {
30 cout << "Error: illegal input to readMinute\n";
31 exit(1);
32 }
33 }
34
35 //Uses iostream, cctype, and cstdlib:
36 void readHour(int& theHour)
37 {
38 char c1, c2;
39 cin >> c1 >> c2;
40 if ( !( isdigit(c1) && (isdigit(c2) || c2 == ’:’ ) ) )
41 {
42 cout << "Error: illegal input to readHour\n";
43 exit(1);
44 }
45 if (isdigit(c1) && c2 == ’:’)
46 {
47 theHour = digitToInt(c1);
48 }
49 else //(isdigit(c1) && isdigit(c2))
50 {
51 theHour = digitToInt(c1)*10 + digitToInt(c2);
52 cin >> c2; //discard ’:’

53 if (c2 != ’:’)
54 {
55 cout << "Error: illegal input to readHour\n";
56 exit(1);
57 }
58 }
59 if (theHour == 24)
60 theHour = 0; //Standardize midnight as 0:00.
61 if ( theHour < 0 || theHour > 23 )
62 {

×