Savitch, Absolute C++ 6/e: Chapter 11, Instructor’s Manual
Full download Absolute C++ 6th Edition Savitch Solutions Manual at: https://testbankpack.com/p/solution-manual-for-absolute-c-6th-edition-savitch-mock0133970787-9780133970784/
Full download Test bank for Absolute C++ 6th Edition Savitch at: https://testbankpack.com/p/test-bank-for-absolute-c-6th-edition-savitch-mock-01339707879780133970784/ Chapter 11
Separate Compilation and Namespaces
Key Terms
interface implementation interface file and implementation file
Private members are part of the implementation. header files include file names application file or driver file compiling and running the program linking linker make project
Why separate files?
#define #ifndef
#endif namespace global namespace scope
namespace grouping using NS1::fun1; using declaration using directive compilation unit
Brief Outline
11.1 Separate Compilation Encapsulation Reviewed
Header Files and Implementation Files
Using #ifndef
11.2 Namespaces
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
Namespaces
and using Directives Creating a Namespace Using Declarations
Qualifying Names
Unnamed Namespace
Pitfall: Confusing Global Namespace and Unnamed Namespace
Nested Namespaces
1. Introduction and Teaching Suggestions
C++ is a language designed by programmers for programmers. This language includes features that support program design and implementation. Separate compilation supports development of code by supporting team programming. Namespaces also support separate compilation by allowing reuse of names.
The ANSI C++ Standard says that the text of a C++ program is kept in one or more source files. A source file together with all the headers that are included via the preprocessor directive, #include, less any lines excluded by conditional inclusion (#ifndef commands) is called a translation unit (sometimes, compilation unit). Changing a set of C++ source files into a C++ program requires running the C++ preprocessor. A C++ program, then, consists of one or more translation (or compilation) units.
Previously translated translation (compilation) units may be preserved as individual object files, or as shared libraries or as static libraries. Separate translation (compilation) units communicate by calls to functions whose identifiers have external linkage, by manipulation of objects whose identifiers have external linkage, or by the manipulation of data files. Translation (compilation) units may be separately compiled and later linked to produce an executable program.
Names are allowed to be defined only once in a C++ program. The notion of namespace was introduced to help prevent name clashes between names in several program components and names in the libraries. The ANSI C++ Standard says “A namespace is an optionally-named declarative region. The name of a namespace is used to access entities declared in that namespace; that is, the member of the namespace.” The C++ standard libraries have header files that declare library names (or define the names, depending on how the library is implemented). The namespace name is std. This is done so that the program can have access to library classes and functions, and the names in the libraries can be both protected from name clash with names in the program.
If using an IDE, then separate compilation can be accomplished using the IDE’s interface. Otherwise, if you are compiling from the command line, then separate compilation is much easier if you use the make facility. Makefiles are not covered in the text but tutorials are readily available online and will be worthwhile for students to cover a bit of code management tools instead of focusing entirely on programming.
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
2. Key Points
Encapsulation Reviewed The principle of encapsulation says to separate the interface and implementation of a class. This means that only thing that should be known to both the author of a class, (or other software system) and the author of software that use the class is the interface and documentation of the class. We summarize here from the text:
1. All member variables of the class should be private.
2. Each basic operation of the class is public member function, a friend function, an ordinary function, or an overloaded operator. Each function should be fully specified so that no knowledge of the implementation will be required to use the operation.
3. Implementations of the operations should be inaccessible to the client programmer. The implementation of a class is the implementation of any operation, no matter whether it is implemented as a class member function, overloaded operator friend or standalone function.
C++ provides a single definition for a class that acts as the interface for both users of the class and implementers of the member functions. There is no direct support for the notions of “interface definition” or “implementation module”. This implies that the size of every object is known to the compiler.
Header Files and Implementation Files. Suppose a program has been split into several files. The functions defined in files which we usually name with a .cpp suffix . can be called in another file provided the functions are declared in the file where they are called, prior to being called. The code authors write header files to supply the declarations. The names of header files usually have a suffix of .h. This divides the code into the implementation file (which should not be available to the client) and the interface file (which the client uses to declare the functions prior to calls.) When used with makefiles, this separation also helps speed up compilation as only files that have changed need to be recompiled.
If the header file is intended to provide an interface and to document the functions in the implementation file, then the header comments should be provided in the header file as well as just the declarations. It is conventional to give the header file and the implementation file the same name apart from the suffix.
Using #ifndef. The #ifndef is one of several conditional compilation commands. A major use is to prevent multiple inclusion of header files. The commands are
#ifndef PROTECT__DTIME_H
#define PROTECT__DTIME_H
// header file here
#endif
If the symbol PROTECT_DTIME_H is defined in the preprocessor symbol table, then the preprocessor will not insert into the temporary file any lines of code up to the next #endif and the compiler will not compile this code. (Failure to put in the #endif is a disaster.) If the symbol PROTECT_DTIME_H is not defined, the next line will define the symbol. The preprocessor will include all lines of code up to the next conditional compilation command. Then the compiler can compile these lines of code.
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
Namespaces. Namespaces support separate compilation by allowing reuse of names. A namespace is a declarative region of the program that may be named or may be unnamed. A namespace is a little like a class in that the names can be accessed by qualification, but is different in that a namespace may be distributed across files. Regardless of whether there is an identical name defined in another namespace, it is possible to provide access to names from namespaces so that the names do not conflict. The header files that the C++ implementation provides for the Standard libraries that do not have the .h extension arrange to place their names into namespace std .
Using Namespaces. The three ways to access a name from a namespace named NS are listed here:
1. Qualifying by the name of the namespace: NS::myFunction(); A qualified name is available in the block where it is used if the header file where the name is defined in the namespace is included. Use of a qualified name within a block does not introduce the name into (i.e., define name within) the block. You can even declare a local name with the same spelling as the qualified name, and use both the qualified name and the local name.
2. A using declaration: using NS::myFunction; After issuing this using definition, the identifier myFunction will be a synonym for NS1::myName. If you write a using declaration within a block, the name is defined within the scope of the block. A name introduced into the block with a using declaration will clash with a local variable of the same name if defined in the same block. Two namespaces with the same name can cause a similar clash. Suppose there are two definitions with the same name, one in each of two namespaces. Placing using declarations of the name from each of the two namespaces in a block results in a name clash.
#include <NS1.h>
#include <NS2.h>
using NS1::myName; using NS2::myName; // error myName already defined.
3. A using directive: using namespace NS; If you write a using directive within a block, all the names from the namespace are made available within the scope of the block. The using directive does not declare the namespace names in the scope; instead, it sets a lookup rule for finding definitions of namespace names used in the scope. This is different from a using declaration, which declares the name declared within the block.
To access the name after a using directive, you just use the name. The declaration in the header and the lookup rule that is provided by the using directive enables the compiler to find the required definition.
Suppose there are two definitions with the same name, one in each of two namespaces. If using directives for two namespaces are placed in a block then the names do not
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
automatically clash. However, use of the name without qualification with the namespace name will cause an ambiguity name error. If you qualify the name, you can use these conflicting names.
Creating a Namespace. Any variable you declare outside all named or unnamed namespaces, blocks, function declarations, function definitions, and classes is put into the global namespace, and is said to have global namespace scope. To put a name into a namespace, whether it already exists or not, place the name into a namespace grouping:
Namespace NS {
//Some definitions of names
Then the names are put into namespace NS.
Unnamed Namespace. If a name of a function, class or variable has file scope, then the name has external linkage. A name has file scope means the name is declared outside any class, function or block. A name has external linkage means the name may be accessed in any other file where that name has been declared. If the name is only accessible to functions and within classes in a file, then the name has internal linkage. That is, we need a way to declare names that have internal linkage. This is done using unnamed namespaces. An unnamed namespace is a namespace where the name of the namespace is omitted.
namespace
void sampleFunction();
The effect is as if the unnamed namespace were given a name unique to the file and a using declaration immediately followed the namespace grouping.
namespace UniqueToThisFile
void sampleFunction();
// other names defined here
using namespace UniqueToThisFile
All names in the namespace UniqueToThisFile are available in this file. They are not visible in any other file because the name of the namespace is created different from any other name in the program, so no namespace declaration with this name can be made there.
Nested Namespaces. Namespaces, like classes, can be nested. Access to an inner name is had by multiple qualification.
namespace Outside {
void name1; namespace Inside { void sample();
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
To call the function void sample() within the inner namespace requires qualification by both namespace names:
Outside::Inside::sample();
3. Tips
Reusable Components A class developed and coded into separate files is a software component that can be reused in a number of different programs.
Defining Other Libraries. You need not define a class in order to use separate compilation. If you have a collection of related functions that you want to make into a library of your own design you can place the prototypes in a header file.
Choosing a Name for a Namespace. It is a good idea to include your last name or some other unique string in the names of your namespace to reduce the chance somebody else will use the same namespace name as you.
Unnamed Namespaces Replace the static Qualifier Earlier versions of C++ used the static qualifier to make a name local to a file. You should instead use the unnamed namespace to make a name local to a compilation unit.
Hiding Helping Functions You can hide helping functions by making them private or by placing it in the unnamed namespace for the implementation file of the class.
4. Pitfalls
Confusing the Global Namespace and the Unnamed Namespace. These are different. If you do not put a name definition in a namespace grouping then it is in the global namespace and it has global scope. Names in an unnamed namespace are local to a compilation unit.
5. Programming Projects Answers
1. Namespaces and Separate Compilation
The files for this project are listed below.
//File: main.cpp
//Compile command: bcc32 main.cpp f.cpp g.cpp
#include "f.h"
#include "g.h"
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
B::g(); return 0;
//file: f.h
namespace A { void f();
//file g.h
namespace B { void g();
//file f.cpp
#include <iostream>
namespace A {
void f(){ std::cout << "A::f() called\n"; }
//file g.cpp
#include <iostream>
namespace B {
void g(){ std::cout << "B::g() called\n";}
To create a namespace or to add to an already created namespace, use a namespace grouping. You can split the definition across files. The declaration and definition of the function void f() follows.
//file: f.h
namespace A {
void f();
One can place the definition of void f() in a namespace grouping, in a separate file if need be. (We are directed by the problem statement to do so here.)
//file f.cpp
#include <iostream>
namespace A {
void f(){ std::cout << "A::f() called\n"; }
Discussion:
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
To be able to call a function defined in your own namespace, you must provide for declarations of the functions prior to the call. This is done with the lines of code, #include "f.h" and #include "g.h". You then separately compile the .cpp files that contain the function definitions, then link, as the compile command in the file listed here.
//File: main.cpp
//Compile command: bcc32 main.cpp f.cpp g.cpp
#include "f.h"
#include "g.h"
int main() { A::f(); B::g(); return 0; }
2. PFArrayD class.
No solution is provided.
3. Extend Chapter 10 Programming Project 1, the TwoD array class.
Place the class definition and implementation in a namespace, then provide access to the names in the namespace. Test. Access to namespace may be by qualification, using definition, or using directive. Global namespace directives are not allowed.
This file, TwoD.h, contains the definition of class TwoD and conditional compilation protection against multiple inclusion.
//************ File: TwoD.h ******************
#ifndef PROTECT_TWOD_H
#define PROTECT_TWOD_H
namespace TD {
typedef double* DoubleArrayPtr; class TwoD {
public:
TwoD(); // sets maxRows and maxCols each to 10 TwoD(int maxR, int maxC);
~TwoD();
TwoD(const TwoD&);
const TwoD& operator=(const TwoD& rhs); double& operator()(int r, int c); // returns row r, col c element double* operator()(int r); //returns pointer to row r. The //return value may be indexed to //extract elements.
friend TwoD operator+(const TwoD& lhs, const TwoD& rhs);
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
friend int myRows(const TwoD&); friend int myCols(const TwoD&);
private:
DoubleArrayPtr * matrix; int maxRows; int maxCols; }; }
#endif
//************* end of file TwoD.h **************
The next file, TwoDApp.cpp, contains the main function and necessary #include commands, as well as a sample run.
//********* File: TwoDApp.cpp ***********
#include <iostream>
#include <cstdlib>
#include "TwoD.h"
int main( ) { using std::exit; using std::cin; using std::cout; using std::endl; using namespace TD;
int d1, d2, i, j;
cout << "Enter the row and column dimensions of the array\n"; cin >> d1 >> d2;
TwoD matrix1(d1, d2);
cout << "Enter " << d1 << " rows of " << d2 << " doubles each\n";
for (i = 0; i < d1; i++)
for (j = 0; j < d2; j++) cin >> matrix1(i,j);
cout << "Echoing the 2 dim. array, matix1\n";
for (i = 0; i < d1; i++)
{ for (j = 0; j < d2; j++)
cout << matrix1(i,j) << " "; cout << endl;
cout << "Enter the row and column dimensions of the array\n"; cin >> d1 >> d2;
TwoD matrix2(d1, d2), matrix3;
cout << "Enter " << d1 << " rows of " << d2 << " doubles each\n";
for (i = 0; i < d1; i++)
for (j = 0; j < d2; j++)
cin >> matrix2(i,j);
cout << "Echoing the 2 dim. array, matrix2\n";
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
for (i = 0; i < myRows(matrix2); i++) {
for (j = 0; j < myCols(matrix2); j++)
cout << matrix2(i, j) << " "; cout << endl;
cout << "assigning matrix 2 to matrix 3 " << endl; matrix3 = matrix2;
cout << "Displaying the 2 dim array, matrix3 " << "resulting from assignment.\n";
cout << "rows " << myRows(matrix3) << " "
<< "cols " << myCols(matrix3) << endl;
for (i = 0; i < myRows(matrix3); i++)
{
for (j = 0; j < myCols(matrix3); j++)
cout << matrix3(i,j) << " "; cout << endl;
matrix3 = matrix2 + matrix1;
cout << "Echoing the 2 dim array, sum of matrix 1 and 2\n";
cout << "rows " << myRows(matrix3) << " "
<< "cols " << myCols(matrix3) << endl;
for (i = 0; i < myRows(matrix3); i++)
{
for (j = 0; j < myCols(matrix3); j++)
{
// cout << "i,j " << i << " " << j << " "; // Debugging cout << matrix3(i,j) << " "; }
cout << endl;
return 0;
/* ******************* SAMPLE RUN *********************
I usually use the command line to execute with input redirected from a file. It is easier than typing in the data every time:
ch10prog1 < ch10prog1Data.txt > ch10prog1out.txt
With this data:
A run produces this output: Enter the row and column dimensions of the array
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
Enter 3 rows of 4 doubles each
Echoing the 2 dim. array, matix1
1 2 3 4
5 6 7 8
9 8 1 2
Enter the row and column dimensions of the array
Enter 3 rows of 4 doubles each
Echoing the 2 dim. array, matrix2
1 1 1 1
-1 -1 -1 -1
2 2 2 2
assigning matrix 2 to matrix 3
Displaying the 2 dim array, matrix3 resulting from assignment.
rows 3 cols 4
1 1 1 1
-1 -1 -1 -1
2 2 2 2
Echoing the 2 dim array, sum of matrix 1 and 2
rows 3 cols 4
2 3 4 5
4 5 6 7 11 10 3 4
**************** END OF SAMPLE RUN ***************
*/
//End of main.cpp
The next file, TwoD.cpp, contains implementations of all members of class TwoD, with other necessary includes and other necessary C++ commands to provide access to the namespace members.
//*************** File: TwoD.cpp *****************
//Implementations
#include <iostream>
#include "TwoD.h"
namespace TD { int myRows(const TwoD& arg){ return arg.maxRows;} int myCols(const TwoD& arg){ return arg.maxCols;}
TwoD operator+(const TwoD& lhs, const TwoD& rhs) { using namespace std; if(lhs.maxRows != rhs.maxRows || lhs.maxCols != rhs.maxCols)
cout << "Matrices not same size "
<< " lhs matrix row, col sizes "
<< lhs.maxRows << " " << lhs.maxCols << endl
<< "rhs matrix row, col sizes "
<< rhs.maxRows << " " << rhs.maxCols << endl; exit(1); // Die if matrices not same.
//sizes are same
TwoD sum(lhs.maxRows, lhs.maxCols);
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
for(int i = 0; i < lhs.maxRows; i++) for(int j = 0; j < lhs.maxCols; j++) sum.matrix[i][j] = rhs.matrix[i][j] + lhs.matrix[i][j];
return sum; }
double& TwoD::operator()(int r, int c) //returns row r, col c //element { return matrix[r][c];
const TwoD& TwoD::operator=(const TwoD& rhs) { if(matrix == rhs.matrix)
return rhs; // lhs == rhs, do nothing
//lhs != rhs, blow away lhs for(int i = 0; i < maxRows; i++) delete[] matrix[i]; delete[] matrix;
maxRows = rhs.maxRows; maxCols = rhs.maxCols;
//reallocate matrix = new DoubleArrayPtr[maxRows]; for(int i = 0; i < maxRows; i++) matrix[i] = new double[maxCols];
//deep copy for(int i = 0; i < maxRows; i++) for(int j = 0; j < maxCols; j++) matrix[i][j] = rhs.matrix[i][j]; return rhs; }
TwoD::TwoD(const TwoD& rhs) : maxRows(rhs.maxRows), maxCols(rhs.maxCols) { matrix = new DoubleArrayPtr[maxRows]; for(int i = 0; i < maxRows; i++) matrix[i] = new double[maxCols];
for(int i = 0; i < maxRows; i++) for(int j = 0; j < maxCols; j++) matrix[i][j] = rhs.matrix[i][j];
TwoD::~TwoD() { for(int i = 0; i < maxRows; i++) delete[] matrix[i]; delete[] matrix;
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
TwoD::TwoD() : maxRows(10), maxCols(10)
{
matrix = new DoubleArrayPtr[maxRows];
for(int i = 0; i < maxRows; i++)
matrix[i] = new double[maxCols];
for(int i = 0; i < maxRows; i++)
for(int j = 0; j < maxCols; j++)
matrix[i][j] = 0;
TwoD::TwoD(int maxR, int maxC ) : maxRows(maxR), maxCols(maxC)
{
matrix = new DoubleArrayPtr[maxRows];
for(int i = 0; i < maxR; i++)
matrix[i] = new double[maxCols];
for(int i = 0; i < maxRows; i++)
for(int j = 0; j < maxCols; j++)
matrix[i][j] = 0;
} // end namespace TD //****************** END OF FILE TwoD.cpp
4. Verify User.
You would like to verify the credentials of a user for your system. Listed below is a class named Security that authenticates a user and password (note that this example is really not very secure, typically passwords would be encrypted or stored in a database):
class Security { public:
static int validate(string username, string password); };
// This subroutine hard-codes valid users and is not // considered a secure practice. // It returns 0 if the credentials are invalid, // 1 if valid user, and
2 if valid administrator
int Security::validate(string username, string password)
if ((username=="abbott") && (password=="monday")) return 1; if ((username=="costello") && (password=="tuesday")) return 2; return 0;
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
Break this class up into two files, a file with the header named Security.h and a file with the implementation named Security.cpp
Next, create two more classes that use the Security class by including the header file. The first class should be named Administrator and contain a method named Login that returns true if a given username and password have administrator clearance. The second class should be named User and contain a method named Login that returns true if a given username and password have either user or administrator clearance.
Both the User and Administrator classes should be split up into separate files for the header and implementation.
Finally, write a main method that invokes the Login method for both the User and Administrator classes to test if they work properly. The main method should be in a separate file. Be sure to use the #ifndef directive to ensure that no header file is included more than once.
//security.h
//This is the header file for the Security class.
// It validates a username and password.
#ifndef __SECURITY_H__
#define __SECURITY_H__
#include <string> using namespace std;
class Security { public: static int validate(string username, string password);
#endif // **************************************************************** // security.cpp
// This class validates a username and password. // It is only an example; it is not very secure. For better // security, passwords would be encrypted and stored in a database // rather than hard-coded into the program.
****************************************************************
#include <iostream>
#include <string>
#include "security.h"
using namespace std;
*****************************
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
// Security::validate
// This subroutine hard-codes valid users and is not
// considered a secure practice.
// It returns 0 if the credentials are invalid,
// 1 if valid user, and // 2 if valid administrator // *****************************
int Security::validate(string username, string password) { if ((username=="abbott") && (password=="monday")) return 1; if ((username=="costello") && (password=="tuesday")) return 2; return 0;
// ****************************************************************
administrator.h
// This is the header file for the Administrator class.
If fully fleshed out it would have more method, but for
purposes of this example there is a single method, Login,
which returns true if a given username and password has
admin clearance.
ENTER YOUR CODE HERE
#ifndef __ADMIN_H__
#define __ADMIN_H__
#include <string> using namespace std;
class Administrator
public:
Administrator();
Administrator(string name, string password); bool Login();
private:
string name; string password;
#endif
END USER CODE
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
// This is the implementation file for the Administrator class.
// If fully fleshed out it would have more method, but for
// purposes of this example there is a single method, Login,
// which returns true if a given username and password has
// admin clearance.
// ****************************************************************
// ENTER YOUR CODE HERE //
#include <iostream>
#include <string>
#include "administrator.h"
#include "security.h" using namespace std;
// *****************************
// Administrator::Administrator
// Constructor that initializes strings to empty.
// ***************************** Administrator::Administrator()
name = ""; password = "";
// *****************************
// Administrator::Administrator
// Constructor that sets values of strings.
// *****************************
Administrator::Administrator(string username, string pass)
name = username; password = pass;
// *****************************
// Administrator::Login
// This method invokes the security validate method
// to determine if the username and password should
// have admin privileges. True is returned if so,
// False otherwise.
// *****************************
bool Administrator::Login()
int result;
result = Security::validate(name,password); if (result==2)
return true;
return false;
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
END USER CODE
user.h
// This is the header file for the user class.
// If fully fleshed out it would have more method, but for
purposes of this example there is a single method, Login,
which returns true if a given username and password has
user clearance.
// ENTER YOUR CODE HERE
#ifndef __USER_H__
#define __USER_H__
#include <string> using namespace std; class User { public: User(); User(string name, string password); bool Login(); private: string name; string password; };
#endif
END USER CODE
****************************************************************
user.cpp
// This is the implementation file for the user class. // If fully fleshed out it would have more method, but for
purposes of this example there is a single method, Login,
which returns true if a given username and password has
user clearance.
ENTER YOUR CODE HERE
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
#include <iostream>
#include <string>
#include "user.h"
#include "security.h" using namespace std;
// *****************************
// User::User
// Constructor that initializes strings to empty.
// *****************************
User::User()
name = ""; password = "";
// *****************************
// User::User
// Constructor that sets values of strings.
// *****************************
User::User(string username, string pass)
{
name = username; password = pass;
// *****************************
// User::Login
// This method invokes the security validate method
// to determine if the username and password should
// have user privileges. True is returned if so,
// False otherwise.
// *****************************
bool User::Login()
int result;
result = Security::validate(name,password); if ((result==2) || (result==1))
return true; } return false;
// Test file to try out the User and Administrator classes.
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
ENTER YOUR CODE HERE
#include <iostream>
#include <string>
#include "user.h"
#include "administrator.h"
using namespace std;
// Main method int main()
// Hard-coded tests. Abbott has User access, Costello has // user and admin access.
User user1("abbott","monday"), user2("lynn","guini"), user3("costello","tuesday"); Administrator admin1("abbott","monday"), admin2("kerry","oki"), admin3("costello","tuesday");
cout << "Results of login:" << endl;
cout << "User login for abbott: " << user1.Login() << endl;
cout << "User login for lynn: " << user2.Login() << endl;
cout << "User login for costello: " << user3.Login() << endl;
cout << "Admin login for abbott: " << admin1.Login() << endl;
cout << "Admin login for lynn: " << admin2.Login() << endl;
cout << "Admin login for costello: " << admin3.Login() << endl; return 0;
5. Exploring Unnamed Namespaces
This Programming Project explores how the unnamed namespace works. Listed below are snippets from a program to perform input validation for a username and password. The code to input and validate the username is in a separate file than the code to input and validate the password.
File header user.cpp: namespace Authenticate { void inputUserName()
cout << "Enter your username (8 letters only)" << endl; cin >> username; } while (!isValid());
string getUserName()
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
return username; }
Define the username variable and the isValid() function in the unnamed namespace so the code will compile. The isValid() function should return true if username contains exactly eight letters. Generate an appropriate header file for this code. Repeat the same steps for the file password.cpp, placing the password variable and the isValid() function in the unnamed namespace. In this case, the isValid() function should return true if the input password has at least 8 characters including at least one non-letter:
File header password.cpp: namespace Authenticate { void inputPassword()
cout << "Enter your password (at least 8 characters " << "and at least one non-letter)" << endl; cin >> password ; } while (!isValid());
string getPassword() { return password;
At this point you should have two functions named isValid(), each in different unnamed namespaces. Place the following main function in an appropriate place. The program should compile and run.
int main() { inputUserName(); inputPassword();
cout << "Your username is " << getUserName() << " and your password is: " << getPassword() << endl; return 0;
Test the program with several invalid usernames and passwords.
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
// File: password.h
#ifndef PASSWORD_H
#define PASSWORD_H
#include <iostream>
#include <string>
using namespace std;
namespace Authenticate { void inputPassword(); string getPassword();
#endif
File: password.cpp
#include <iostream>
#include <string>
#include <cctype> using namespace std;
namespace { string password; bool isValid()
if (password.length() >= 8)
for (int i=0; i<password.length(); i++) if (!isalpha(password[i])) return true;
} return false;
namespace Authenticate { void inputPassword()
cout << "Enter your password (at least 8" << " characters and at least one non-letter)" << endl; cin >> password; } while (!isValid());
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
string getPassword() { return password;
// File: user.h
#ifndef USERNAME_H
#define USERNAME_H
#include <iostream>
#include <string>
using namespace std;
namespace Authenticate
void inputUserName(); string getPassword();
#endif
// File: user.cpp
#include <iostream>
#include <string> using namespace std;
namespace { string username; bool isValid()
if (username.length() == 8) return true; return false;
namespace Authenticate
void inputUserName()
do
cout << "Enter your username " << "(8 letters only)" << endl;
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.
Savitch, Absolute C++ 6/e: Chapter 11, Instructor’s Manual
cin >> username; } while (!isValid());
string getUserName() { return username;
// File: main.cpp /////////////////////////////
#include <iostream>
#include "password.h"
#include "username.h" using namespace std; using namesapce Authenticate; int main() {
inputUserName(); inputPassword();
cout << "Your username is " << getUserName() << " and your password is: " << getPassword() << endl;
cout << "Enter a character to exit." << endl; char wait; cin >> wait; return 0;
Copyright © 2016 Pearson Education Addison-Wesley. All rights reserved.