Let’s take a look at a multifile example that demonstrates some of the features of namespaces. The first file in this example (see Listing 9.11) is a header file that contains some items normally found in header files—constants, structure definitions, and function prototypes. In this case, the items are placed in two namespaces. The first namespace, pers
, contains a definition of a Person
structure, plus prototypes for a function that fills a structure with a person’s name and a function that displays the structure’s contents. The second namespace, debts
, defines a structure for storing the name of a person and the amount of money owed to that person. This structure uses the Person
structure, so the debts
namespace has a using
directive to make the names in the pers
namespace available in the debts
namespace. The debts
namespace also contains some prototypes.
// namesp.h
#include <string>
// create the pers and debts namespaces
namespace pers
{
struct Person
{
std::string fname;
std::string lname;
};
void getPerson(Person &);
void showPerson(const Person &);
}
namespace debts
{
using namespace pers;
struct Debt
{
Person name;
double amount;
};
void getDebt(Debt &);
void showDebt(const Debt &);
double sumDebts(const Debt ar[], int n);
}
The second file in this example (see Listing 9.12) follows the usual pattern of having a source code file provide definitions for functions prototyped in a header file. The function names, which are declared in a namespace, have namespace scope, so the definitions need to be in the same namespace as the declarations. This is where the open nature of namespaces comes in handy. The original namespaces are brought in by including namesp.h
(refer to Listing 9.11). The file then adds the function definitions to the two namespaces, as shown in Listing 9.12. Also the namesp.cpp
file illustrates bringing in elements of the std
namespace with the using
declaration and the scope-resolution operator.
// namesp.cpp -- namespaces
#include <iostream>
#include "namesp.h"
namespace pers
{
using std::cout;
using std::cin;
void getPerson(Person & rp)
{
cout << "Enter first name: ";
cin >> rp.fname;
cout << "Enter last name: ";
cin >> rp.lname;
}
void showPerson(const Person & rp)
{
std::cout << rp.lname << ", " << rp.fname;
}
}
namespace debts
{
void getDebt(Debt & rd)
{
getPerson(rd.name);
std::cout << "Enter debt: ";
std::cin >> rd.amount;
}
void showDebt(const Debt & rd)
{
showPerson(rd.name);
std::cout <<": $" << rd.amount << std::endl;
}
double sumDebts(const Debt ar[], int n)
{
double total = 0;
for (int i = 0; i < n; i++)
total += ar[i].amount;
return total;
}
}
Finally, the third file of this program (see Listing 9.13) is a source code file that uses the structures and functions declared and defined in the namespaces. Listing 9.13 shows several methods of making the namespace identifiers available.
// usenmsp.cpp -- using namespaces
#include <iostream>
#include "namesp.h"
void other(void);
void another(void);
int main(void)
{
using debts::Debt;
using debts::showDebt;
Debt golf = { {"Benny", "Goatsniff"}, 120.0 };
showDebt(golf);
other();
another();
return 0;
}
void other(void)
{
using std::cout;
using std::endl;
using namespace debts;
Person dg = {"Doodles", "Glister"};
showPerson(dg);
cout << endl;
Debt zippy[3];
int i;
for (i = 0; i < 3; i++)
getDebt(zippy[i]);
for (i = 0; i < 3; i++)
showDebt(zippy[i]);
cout << "Total debt: $" << sumDebts(zippy, 3) << endl;
return;
}
void another(void)
{
using pers::Person;
Person collector = { "Milo", "Rightshift" };
pers::showPerson(collector);
std::cout << std::endl;
}
In Listing 9.13, main()
begins by using two using
declarations:
using debts::Debt; // makes the Debt structure definition available
using debts::showDebt; // makes the showDebt function available
Note that using
declarations just use the name; for example, the second example here doesn’t describe the return type or function signature for showDebt
; it just gives the name. (Thus, if a function were overloaded, a single using
declaration would import all the versions.) Also although both Debt
and showDebt()
use the Person
type, it isn’t necessary to import any of the Person
names because the debt
namespace already has a using
directive that includes the pers
namespace.
Next, the other()
function takes the less desirable approach of importing the entire namespace with a using
directive:
using namespace debts; // make all debts and pers names available to other()
Because the using
directive in debts
imports the pers
namespace, the other()
function can use the Person
type and the showPerson()
function.
Finally, the another()
function uses a using
declaration and the scope-resolution operator to access specific names:
using pers::Person;;
pers::showPerson(collector);
Here is a sample run of the program built from Listings 9.11, 9.12, and 9.13:
Goatsniff, Benny: $120
Glister, Doodles
Enter first name: Arabella
Enter last name: Binx
Enter debt: 100
Enter first name: Cleve
Enter last name: Delaproux
Enter debt: 120
Enter first name: Eddie
Enter last name: Fiotox
Enter debt: 200
Binx, Arabella: $100
Delaproux, Cleve: $120
Fiotox, Eddie: $200
Total debt: $420
Rightshift, Milo
3.15.31.22