9.3 Namespaces
namespace problems
The conflict of using same-name things from different libraries. For example, two libraries might both define classes named List, Tree abd Node. Using them might cause namespace problems.
9.3.1 Traditional C++ namespaces
declarative region
A declaration region is a region in which declaration could be made. For instance, if you declare a variable inside a function, its declaration region is the innermost block in which it is declared.
potential scope
Begins at its point of declaration and extends to its end of the declarative region. (smaller than declarative region, not involving parts before the declaration is made)
scope
The region that the variable is actually visible. For example, if you define variables with the same name in inner blocks, the outer one would be hided, thus the block in which the new variable with the same name is defined should not be part of the old variable's scope.
9.3.2 New namespace features
) C++ adds the ability of creating a declarative region just for name declarations called namespace. Names in one namespace don't conflict with the same names declared in other namespcaes.
namespace Jack
{
double pail;
void fetch();
int pal;
struct Well {...};
}
namespace Jill
{
double bucket(double n) {...}
double fetch;
int pal;
struct Hill {...};
}
In the below example, two fetch in two namespaces, one function and one double varaible won't conflict with each other.
In addition to user-defined namespaces, there is a global namespace, what used to be termed global variables are now part of the global namespace.
) You can add names to existing namespaces:
namespace Jill
{
char * goose(const char *);
}
This adds goose to the existing namespace Jill.
) You can provide function definition declared in a namespace:
namespace Jack
{
void fetch()
{
...
}
}
) To access names in a namespace, use scope-resolution operator(::) to qualify a name with its namespace:
Jack::pail = 12.34;
Jill:Hill mole;
Jack::fetch();
using declarations
The using declaration makes one name in the namespace available, adding a particular name to the declarative region in which it occurs:
using Jill:fetch;
After that point of using declaration, you could use the name fetch just the same as Jill:fetch:
cin >> fetch; // taken for Jill::fetch
using directives
The using directive makes all the names available:
using namespace Jack;
From that point of directive, every name in Jack could be used without Jack::. Same name variables would also be taken for they are defined in Jack.
) using directives and using declarations increase the possibility of name conflicts.
) If a particular name is already declared in a function:
You can't use using declarations, it will raise an error
You can use using directive, but the local version hides the namespace version
namespace Jill
{
double fetch;
}
char fetch;
int main()
{
double fetch;
cin >> fetch; // local fetch
cin >> ::fetch; // global fetch
cin >> Jill::fetch; // namespace fetch
}
This example illustrates that you could still access the global and namespace versions even they are hidden by the local one, using ::.
) Generally speaking, it is safer to use using declarations than using directives. (using declarations warn you of name conflicts but directives don't)
) You can nest namespace declarations, you can use using declarations and directives in namespaces, using directives is transitive(which means that if namespace A contains namespace B, while using namespace A will also cause namespace B to be used with the using directive, equivalent to two separate using directives for A and B),you can also make alias for namespaces:
namespace MEF = myth::elements::fire;
using MEF::flame;
) You can also create unnamed namespaces, which behaves as if it was followed by a using directive, its potential scope extends to where its declaration region ends. You could also create static variables with internal linkage with unnamed namespaces:
static int counts; // static storage, internal linkage
is equivalent to
namespace
{
int counts; // static storage, internal linkage
}
9.3.3 A namespace example
#include <string>
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);
}
// 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;
}
}
// 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 = {"Doodle", "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;
}
9.3.4 Namespaces and the future
) Place a using directive after all the preprocessor #include directives
) Use more using declaration and ::, mostly local scope
) Developing a library of functions or classes, place them in a namespace
Exercise 4:
// Ex4.h
#ifndef EX4_H_INCLUDED
#define EX4_H_INCLUDED
namespace SALES
{
const int QUARTERS = 4;
struct Sales
{
double sales[QUARTERS];
double average;
double max;
double min;
};
void setSales(Sales & s, const double ar[], int n);
void setSales(Sales & s);
void showSales(const Sales & s);
}
#endif // EX4_H_INCLUDED
// Ex4_1.cpp
#include <iostream>
#include "Ex4.h"
namespace SALES
{
void setSales(Sales & s, const double ar[], int n)
{
for (int i = 0; i < n; i++)
s.sales[i] = ar[i];
for (int i = n; i < 4; i++)
s.sales[i] = 0;
double total;
s.max = 0;
s.min = 100;
for (int i = 0; i < 4; i++)
{
total += s.sales[i];
if (s.sales[i] > s.max) s.max = s.sales[i];
if (s.sales[i] < s.min) s.min = s.sales[i];
}
s.average = total / 4;
}
void setSales(Sales & s)
{
for (int i = 0; i < 4; i++)
{
std::cout << "Enter quarter " << i+1 << ": ";
std::cin >> s.sales[i];
}
double total;
s.max = 0;
s.min = 100;
for (int i = 0; i < 4; i++)
{
total += s.sales[i];
if (s.sales[i] > s.max) s.max = s.sales[i];
if (s.sales[i] < s.min) s.min = s.sales[i];
}
s.average = total / 4;
}
void showSales(const Sales & s)
{
for (int i = 0; i < 4; i++)
std::cout << "The sales of quarter " << i+1 << " is " << s.sales[i] << std::endl;
std::cout << "The average is " << s.average << " while max and min is " << s.max << " " << s.min << std::endl;
}
}
//Ex4_2.cpp
#include <iostream>
#include "Ex4.h"
int main()
{
using namespace SALES;
Sales s1;
setSales(s1);
Sales s2;
double sa[4] = {1,2,3,4};
setSales(s2, sa, 4);
showSales(s1);
showSales(s2);
return 0;
}