0% found this document useful (0 votes)
6 views24 pages

Week 14 Final Hearder Files & Separate Interfacing

The document discusses the importance of placing class definitions in separate header files for reusability in C++ programming. It explains how to avoid compilation errors caused by multiple main functions and emphasizes the separation of a class's interface from its implementation. The document also outlines the structure of header files and source code files, illustrating how to define and use classes effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views24 pages

Week 14 Final Hearder Files & Separate Interfacing

The document discusses the importance of placing class definitions in separate header files for reusability in C++ programming. It explains how to avoid compilation errors caused by multiple main functions and emphasizes the separation of a class's interface from its implementation. The document also outlines the structure of header files and source code files, illustrating how to define and use classes effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 24

WEEK # 9

OOP’S
HEADER FILES,
PLACING SEPARATE
INTERFACING
Placing a Class in a Separate File for
Reusability
When we have successfully developed a class XYZ as far as we
need to for now from a programming perspective, so let's
consider some software engineering issues. One of the benefits
of creating class definitions is that, when packaged properly,
our classes can be reused by programmers potentially
worldwide. For example, we can reuse C++ Standard Library
type string in any C++ program by including the header file
<string> in the program (and, as we will see, by being able to
link to the library's object code).

Unfortunately, programmers who wish to use our XYZ class


cannot simply include the file in another program. As we have
already learned, function main begins the execution of every
program, and every program must have exactly one main
function. If other programmers include the code, they get extra
baggage our main function and their programs will then have
two main functions. When they attempt to compile their
programs, the compiler will indicate an error because, again,
each program can have only one main function. For example,
attempting to compile a program with two main functions in
Microsoft Visual C++ .NET produces the error

error C2084: function 'int main(void)' already has a body


when the compiler tries to compile the second main function it
encounters.

These errors indicate that a program already has a main


function. So, placing main in the same file with a class
definition prevents that class from being reused by other
programs. In this section, we demonstrate how to make
class XYZ reusable by separating it into another file from the
main function.

Header Files
Each of the previous examples in the chapter consists of a
single .cpp file, also known as a source-code file that contains a
GradeBook class definition and a main function. When building
an object-oriented C++ program, it is customary to define
reusable source code (such as a class) in a file that by
convention has a .h filename extension known as a header file.
Programs use #include preprocessor directives to include
header files and take advantage of reusable software
components, such as type string provided in the C++
Standard Library and user-defined types like class
GradeBook.

Reference: [Page 96] OF THE BOOK C++ HOT TO PROGRAM (DIETEL & DIETEL)
In our next example, we separate the code from Fig. 3.7 into
two files GradeBook.h (Fig. 3.9) and fig03_10.cpp (Fig. 3.10). As
you look at the header file in Fig. 3.9, notice that it contains
only the GradeBook class definition (lines 1141) and lines 38,
which allow class GradeBook to use cout, endl and type string.
The main function that uses class GradeBook is defined in the
source-code file fig03_10.cpp (Fig. 3.10) at lines 1021. To help
you prepare for the larger programs you will encounter later in
this book and in industry, we often use a separate source-code
file containing function main to test our classes (this is called a
driver program). You will soon learn how a source-code file
with main can use the class definition found in a header file to
create objects of a class.

Figure 3.9. GradeBook class definition.


(This item is displayed on pages 96 - 97 in the print version)
1 // Fig. 3.9: GradeBook.h
2 // GradeBook class definition in a separate file from main.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6
7 #include <string> // class GradeBook uses C++ standard string class
8 using std::string;
9
10 // GradeBook class definition
11 class GradeBook
12 {
13 public:
14 // constructor initializes courseName with string supplied as argument
15 GradeBook( string name )
16 {
17 setCourseName( name ); // call set function to initialize courseName
18 } // end GradeBook constructor
19
20 // function to set the course name
21 void setCourseName( string name )
22 {
23 courseName = name; // store the course name in the object
24 } // end function setCourseName
25
26 // function to get the course name
27 string getCourseName()
28 {
29 return courseName; // return object's courseName
30 } // end function getCourseName
31
32 // display a welcome message to the GradeBook user
33 void displayMessage()
34 {
35 // call getCourseName to get the courseName
36 cout << "Welcome to the grade book for\n" << getCourseName()
37 << "!" << endl;
38 } // end function displayMessage
39 private:
40 string courseName; // course name for this GradeBook
41 }; // end class GradeBook

Including a Header File That Contains a


User-Defined Class
A header file such as GradeBook.h (Fig. 3.9) cannot be used to
begin program execution, because it does not contain a main
function. If you try to compile and link GradeBook.h by itself to
create an executable application, Microsoft Visual C++ .NET will
produce the linker error message:
error LNK2019: unresolved external symbol _main referenced in
function _mainCRTStartup

The compiler knows what fundamental data types like int are,
the compiler does not know what a GradeBook is because it is a
user-defined type. In fact, the compiler does not even know the
classes in the C++ Standard Library. To help it understand how
to use a class, we must explicitly provide the compiler with the
class's definition that's why, for example, to use type string, a
program must include the <string> header file. This enables the
compiler to determine the amount of memory that it must
reserve for each object of the class and ensure that a program
calls the class's member functions correctly.
Figure 3.10. Including class GradeBook from file
GradeBook.h for use in main.
1 // Fig. 3.10: fig03_10.cpp
2 // Including class GradeBook from file GradeBook.h for use in
main.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6
7 #include "GradeBook.h" // include definition of class
GradeBook
8
9 // function main begins program execution
10 int main()
11 {
12 // create two GradeBook objects
13 GradeBook gradeBook1( "CS101 Introduction to C++
Programming" );
14 GradeBook gradeBook2( "CS102 Data Structures in C++" );
15
16 // display initial value of courseName for each GradeBook
17 cout << "gradeBook1 created for course: " <<
gradeBook1.getCourseName()
18 << "\ngradeBook2 created for course: " <<
gradeBook2.getCourseName()
19 << endl;
20 return 0; // indicate successful termination
21 } // end main
gradeBook1 created for course: CS101 Introduction to C++
Programming
gradeBook2 created for course: CS102 Data Structures in C++

To create GradeBook objects gradeBook1 and gradeBook2 in


lines 1314 of Fig. 3.10, the compiler must know the size of a
GradeBook object. While objects conceptually contain data
members and member functions, C++ objects typically contain
only data. The compiler creates only one copy of the class's
member functions and shares that copy among all the class's
objects. Each object, of course, needs its own copy of the
class's data members, because their contents can vary
among objects (such as two different BankAccount
objects having two different balance data members).
The member function code, however, is not modifiable, so it
can be shared among all objects of the class. Therefore, the size
of an object depends on the amount of memory required to
store the class's data members. By including GradeBook.h in
line 7, we give the compiler access to the information it needs
(Fig. 3.9, line 40) to determine the size of a GradeBook object
and to determine whether objects of the class are used
correctly (in lines 1314 and 1718 of Fig. 3.10).
How Header Files Are Located
Notice that the name of the GradeBook.h header file in line 7 of
Fig. 3.10 is enclosed in quotes (" ") rather than angle brackets
(< >). Normally, a program's source-code files and user-defined
header files are placed in the same directory. When the
preprocessor encounters a header file name in quotes (e.g.,
"GradeBook.h"), the preprocessor attempts to locate the
header file in the same directory as the file in which the
#include directive appears. If the preprocessor cannot find the
header file in that directory, it searches for it in the same
location(s) as the C++ Standard Library header files. When the
preprocessor encounters a header file name in angle brackets
(e.g., <iostream>), it assumes that the header is part of the C+
+ Standard Library and does not look in the directory of the
program that is being preprocessed.

NOTE: To ensure that the preprocessor can locate header


files correctly, #include preprocessor directives should place
the names of user-defined header files in quotes (e.g.,
"GradeBook.h") and place the names of C++ Standard Library
header files in angle brackets (e.g., <iostream>).
Separating Interface from
Implementation
In the preceding section, we showed how to promote software
reusability by separating a class definition from the client code
(e.g., function main) that uses the class. We now introduce
another fundamental principle of good software engineering
separating interface from implementation.

Interface of a Class
Interfaces define and standardize the ways in which things such
as people and systems interact with one another. For example,
a radio's controls serve as an interface between the radio's
users and its internal components. The controls allow users to
perform a limited set of operations (such as changing the
station, adjusting the volume, and choosing between AM and
FM stations). Various radios may implement these operations
differently some provide push buttons, some provide dials and
some support voice commands. The interface specifies what
operations a radio permits users to perform but does not
specify how the operations are implemented inside the radio.

Similarly, the interface of a class describes what services a


class's clients can use and how to request those services, but
not how the class carries out the services. A class's interface
consists of the class's public member functions (also known as
the class's public services). For example, class GradeBook's
interface (Fig. 3.9) contains a constructor and member
functions setCourseName, getCourseName and
displayMessage. GradeBook's clients (e.g., main in Fig. 3.10) use
these functions to request the class's services. As you will soon
see, you can specify a class's interface by writing a class
definition that lists only the member function names, return
types and parameter types.

Separating the Interface from the


Implementation
In our prior examples, each class definition contained the
complete definitions of the class's public member functions and
the declarations of its private data members. However, it is
better software engineering to define member functions
outside the class definition, so that their implementation
details can be hidden from the client code. This practice
ensures that programmers do not write client code that
depends on the class's implementation details. If they were to
do so, the client code would be more likely to "break" if the
class's implementation changed.

The following program of Figs. 3.11 till Figs. 3.13 separates


class GradeBook's interface from its implementation by splitting
the class definition of Fig. 3.9 into two files the header file
GradeBook.h (Fig. 3.11) in which class GradeBook is defined,
and the source-code file GradeBook.cpp (Fig. 3.12) in which
GradeBook's member functions are defined. By convention,
member-function definitions are placed in a source-code file
of the same base name (e.g., GradeBook) as the class's header
file but with a .cpp filename extension. The source-code file
fig03_13.cpp (Fig. 3.13) defines function main (the client code).
The code and output of Fig. 3.13 are identical to that of Fig.
3.10. Figure 3.14 shows how this three-file program is
compiled from the perspectives of the GradeBook class
programmer and the client-code programmer we will explain
this figure in detail.

GradeBook.h: Defining a Class's


Interface with Function Prototypes

Header file GradeBook.h (Fig. 3.11) contains another version of


GradeBook's class definition (lines 918). This version is similar
to the one in Fig. 3.9, but the function definitions in Fig. 3.9 are
replaced here with function prototypes (lines 1215) that
describe the class's public interface without revealing the
class's member function implementations. A function prototype
is a declaration of a function that tells the compiler the
function's name, its return type and the types of its parameters.
Note that the header file still specifies the class's private data
member (line 17) as well. Again, the compiler must know the
data members of the class to determine how much memory to
reserve for each object of the class. Including the header file
GradeBook.h in the client code (line 8 of Fig. 3.13) provides the
compiler with the information it needs to ensure that the client
code calls the member functions of class GradeBook correctly.

The function prototype in line 12 (Fig. 3.12) indicates that the


constructor requires one string parameter. Recall that
constructors do not have return types, so no return type
appears in the function prototype. Member function
setCourseName's function prototype (line 13) indicates that
setCourseName requires a string parameter and does not
return a value (i.e., its return type is void). Member function
getCourseName's function prototype (line 14) indicates that the
function does not require parameters and returns a string.
Finally, member function displayMessage's function prototype
(line 15) specifies that displayMessage does not require
parameters and does not return a value. These function
prototypes are the same as the corresponding function headers
in Fig. 3.9, except that the parameter names (which are
optional in prototypes) are not included and each function
prototype must end with a semicolon.

[Page 101]

Figure 3.11. GradeBook class definition containing function prototypes that specify the
interface of the class.
(This item is displayed on page 100 in the print version)

1 // Fig. 3.11: GradeBook.h


2 // GradeBook class definition. This file presents GradeBook's public
3 // interface without revealing the implementations of GradeBook's
member
4 // functions, which are defined in GradeBook.cpp.
5 #include <string> // class GradeBook uses C++ standard string class
6 using std::string;
7
8 // GradeBook class definition
9 class GradeBook
10 {
11 public:
12 GradeBook( string ); // constructor that initializes courseName
13 void setCourseName( string ); // function that sets the course name
14 string getCourseName(); // function that gets the course name
15 void displayMessage(); // function that displays a welcome message
16 private:
17 string courseName; // course name for this GradeBook
18 }; // end class GradeBook
GradeBook.cpp: Defining Member
Functions in a Separate Source-Code File
Source-code file GradeBook.cpp (Fig. 3.12) defines class
GradeBook's member functions, which were declared in lines
1215 of Fig. 3.11. The member-function definitions appear in
lines 1134 and are nearly identical to the member-function
definitions in lines 1538 of Fig. 3.9.
Notice that each member function name in the function
headers (lines 11, 17, 23 and 29) is preceded by the class name
and ::, which is known as the binary scope resolution operator.
This "ties" each member function to the (now separate)
GradeBook class definition, which declares the class's member
functions and data members. Without "GradeBook::" preceding
each function name, these functions would not be recognized
by the compiler as member functions of class GradeBook the
compiler would consider them "free" or "loose" functions, like
main. Such functions cannot access GradeBook's private data or
call the class's member functions, without specifying an object.
So, the compiler would not be able to compile these functions.
For example, lines 19 and 25 that access variable courseName
would cause compilation errors because courseName is not
declared as a local variable in each function the compiler would
not know that courseName is already declared as a data
member of class GradeBook.
Common Programming Error 3.9
When defining a class's member functions outside that class,
omitting the class name and binary scope resolution operator
(::) preceding the function names causes compilation errors.

To indicate that the member functions in GradeBook.cpp are


part of class GradeBook, we must first include the GradeBook.h
header file (line 8 of Fig. 3.12). This allows us to access the class
name GradeBook in the GradeBook.cpp file. When compiling
GradeBook.cpp, the compiler uses the information in
GradeBook.h to ensure that

[Page 102]

1. the first line of each member function (lines 11, 17, 23 and
29) matches its prototype in the GradeBook.h file for
example, the compiler ensures that getCourseName
accepts no parameters and returns a string.
2. each member function knows about the class's data
members and other member functions for example, lines
19 and 25 can access variable courseName because it is
declared in GradeBook.h as a data member of class
GradeBook, and lines 13 and 32 can call functions
setCourseName and getCourseName, respectively,
because each is declared as a member function of the class
in GradeBook.h (and because these calls conform with the
corresponding prototypes).

Figure 3.12. GradeBook member-function definitions


represent the implementation of class GradeBook.

1 // Fig. 3.12: GradeBook.cpp


2 // GradeBook member-function definitions. This file contains
3 // implementations of the member functions prototyped in
GradeBook.h.
4 #include <iostream>
5 using std::cout;
6 using std::endl;
7
8 #include "GradeBook.h" // include definition of class
GradeBook
9
10 // constructor initializes courseName with string supplied as argument
11 GradeBook::GradeBook( string name )
12 {
13 setCourseName( name ); // call set function to initialize courseName
14 } // end GradeBook constructor
15
16 // function to set the course name
17 void GradeBook::setCourseName( string name )
18 {
19 courseName = name; // store the course name in the object
20 } // end function setCourseName
21
22 // function to get the course name
23 string GradeBook::getCourseName()
24 {
25 return courseName; // return object's courseName
26 } // end function getCourseName
27
28 // display a welcome message to the GradeBook user
29 void GradeBook::displayMessage()
30 {
31 // call getCourseName to get the courseName
32 cout << "Welcome to the grade book for\n" <<
getCourseName()
33 << "!" << endl;
34 } // end function displayMessage
Testing Class GradeBook
Figure 3.13 performs the same GradeBook object
manipulations as Fig. 3.10. Separating GradeBook's interface
from the implementation of its member functions does not
affect the way that this client code uses the class. It affects
only how the program is compiled and linked, which we discuss
in detail shortly.

[Page 103]

Figure 3.13. GradeBook class demonstration after separating its interface


from its implementation.

1 // Fig. 3.13: fig03_13.cpp


2 // GradeBook class demonstration after separating
3 // its interface from its implementation.
4 #include <iostream>
5 using std::cout;
6 using std::endl;
7
8 #include "GradeBook.h" // include definition of class GradeBook
9
10 // function main begins program execution
11 int main()
12 {
13 // create two GradeBook objects
14 GradeBook gradeBook1( "CS101 Introduction to C++ Programming");
15 GradeBook gradeBook2( "CS102 Data Structures in C++" );
16
17 // display initial value of courseName for each GradeBook
18 cout << "gradeBook1 created for course: " << gradeBook1.getCourseName()
19 << "\ngradeBook2 created for course: " << gradeBook2.getCourseName()
20 << endl;
21 return 0; // indicate successful termination
22 } // end main

gradeBook1 created for course: CS101 Introduction to C++


Programming
gradeBook2 created for course: CS102 Data Structures in C++

As in Fig. 3.10, line 8 of Fig. 3.13 includes the GradeBook.h


header file so that the compiler can ensure that GradeBook
objects are created and manipulated correctly in the client
code. Before executing this program, the source-code files in
Fig. 3.12 and Fig. 3.13 must both be compiled, then linked
togetherthat is, the member-function calls in the client code
need to be tied to the implementations of the class's member
functions a job performed by the linker.
The Compilation and Linking Process
The diagram in Fig. 3.14 shows the compilation and linking
process that results in an executable GradeBook application
that can be used by instructors. Often a class's interface and
implementation will be created and compiled by one
programmer and used by a separate programmer who
implements the class's client code. So, the diagram shows what
is required by both the class-implementation programmer and
the client-code programmer. The dashed lines in the diagram
show the pieces required by the class-implementation
programmer, the client-code programmer and the GradeBook
application user, respectively. [Note: Figure 3.14 is not a UML
diagram.]

Figure 3.14. Compilation and linking process that produces an


executable application.
A class-implementation programmer responsible for creating a
reusable GradeBook class creates the header file GradeBook.h
and source-code file GradeBook.cpp that #includes the header
file, then compiles the source-code file to create GradeBook's
object code. To hide the implementation details of GradeBook's
member functions, the class-implementation programmer would
provide the client-code programmer with the header file
GradeBook.h (which specifies the class's interface and data
members) and the object code for class GradeBook which
contains the machine-language instructions that represent
GradeBook's member functions. The client-code programmer is
not given GradeBook's source-code file, so the client remains
unaware of how GradeBook's member functions are
implemented.

[Page 104]

[Page 105]

The client code needs to know only GradeBook's interface to


use the class and must be able to link its object code. Since the
interface of the class is part of the class definition in the
GradeBook.h header file, the client-code programmer must have
access to this file and #include it in the client's source-code file.
When the client code is compiled, the compiler uses the class
definition in GradeBook.h to ensure that the main function
creates and manipulates objects of class GradeBook correctly.
To create the executable GradeBook application to be used by
instructors, the last step is to link
1. the object code for the main function (i.e., the client code)
2. the object code for class GradeBook's member function
implementations
3. the C++ Standard Library object code for the C++ classes
(e.g., string) used by the class implementation programmer
and the client-code programmer.
The linker's output is the executable GradeBook application that
instructors can use to manage their students' grades.
References:

1. https://www.geeksforgeeks.org/c-classes-and-objects/

2. https://www.w3schools.com/cpp/cpp_access_specifiers.asp

3. https://www.geeksforgeeks.org/playing-with-destructors-in-c/

You might also like