Object-Oriented Programming (OOP) in C++
Object-Oriented Programming (OOP) in C++
C++ Programming
1.1 Traditional Procedural-Oriente
1.2 Object-Oriented Programming
1.3 Benefits of OOP
Language 2. OOP Basics
2.1 Classes & Instances
2.2 A Class is a 3-Compartment Bo
Object-Oriented 2.3 Class Definition
2.4 Creating Instances of a Class
Programming (OOP) in 2.5 Dot (.) Operator
2.6 Data Members (Variables)
C++ 2.7 Member Functions
2.8 Putting them Together: An OO
2.9 Constructors
2.10 Default Arguments for Functi
2.11 "public" vs. "private" Acce
1. Why OOP? 2.12 Information Hiding and Enca
2.13 Getters and Setters
Suppose that you want to assemble your own PC, you go to a hardware store 2.14 Keyword "this"
and pick up a motherboard, a processor, some RAMs, a hard disk, a casing, a 2.15 "const" Member Functions
power supply, and put them together. You turn on the power, and the PC 2.16 Convention for Getters/Sette
runs. You need not worry whether the motherboard is a 4-layer or 6-layer 2.17 Default Constructor
board, whether the hard disk has 4 or 6 plates; 3 inches or 5 inches in diameter, 2.18 Constructor's Member Initiali
whether the RAM is made in Japan or Korea, and so on. You simply put the 2.19 *Destructor
hardware components together and expect the machine to run. Of course, you 2.20 *Copy Constructor
have to make sure that you have the correct interfaces, i.e., you pick an IDE 2.21 *Copy Assignment Operator
hard disk rather than a SCSI hard disk, if your motherboard supports only IDE; 3. Separating Header and Impleme
you have to select RAMs with the correct speed rating, and so on. 4. Example: The Circle Class
Nevertheless, it is not difficult to set up a machine from hardware components.
5. Example: The Time Class
Similarly, a car is assembled from parts and components, such as chassis, doors, 6. Example: The Point Class
engine, wheels, brake, and transmission. The components are reusable, e.g., a 7. Example: The Account Class
wheel can be used in many cars (of the same specifications). 8. Example: The Ball class
Hardware, such as computers and cars, are assembled from parts, which are 9. Example: The Author and Book
reusable components. 9.1 Let's start with the Author cla
9.2 A Book is written by an Autho
How about software? Can you "assemble" a software application by picking a
9.3 Pass-by-Reference for Objects
routine here, a routine there, and expect the program to run? The answer is
obviously no! Unlike hardware, it is very difficult to "assemble" an application
from software components. Since the advent of computer 60 years ago, we
have written tons and tons of programs. However, for each new application, we have to re-invent the wheels and write
the program from scratch.
Traditional procedural-oriented languages (such as C and Pascal) suffer some notable drawbacks in creating reusable
software components:
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 1/39
12/21/2019 Object-oriented Programming (OOP) in C++
In the early 1970s, the US Department of Defense (DoD) commissioned a task force to investigate why its IT
budget always went out of control; but without much to show for. The findings are:
1. 80% of the budget went to the software (while the remaining 20% to the hardware).
2. More than 80% of the software budget went to maintenance (only the remaining 20% for new software
development).
3. Hardware components could be applied to various products, and their integrity normally did not affect
other products. (Hardware can share and reuse! Hardware faults are isolated!)
4. Software procedures were often non-sharable and not reusable. Software faults could affect other
programs running in computers.
The task force proposed to make software behave like hardware OBJECT. Subsequently, DoD replaces over 450
computer languages, which were then used to build DoD systems, with an object-oriented language called Ada.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 2/39
12/21/2019 Object-oriented Programming (OOP) in C++
as Java, C++, C#) let you think in the problem space, and use software objects to represent and abstract entities of
the problem space to solve the problem.
Most importantly, some of these classes (such as Ball and Audience) can be reused in another application, e.g.,
computer basketball game, with little or no modification.
1.3 Benefits of OOP
The procedural-oriented languages focus on procedures, with function as the basic unit. You need to first figure out all
the functions and then think about how to represent data.
The object-oriented languages focus on components that the user perceives, with objects as the basic unit. You figure out
all the objects by putting all the data and operations that describe the user's interaction with the data.
2. OOP Basics
Instance : An instance is a realization of a particular item of a class. In other words, an instance is an instantiation of a
class. All the instances of a class have similar properties, as described in the class definition. For example, you can define a
class called "Student" and create three instances of the class "Student" for "Peter", "Paul" and "Pauline".
The term "object" usually refers to instance. But it is often used quite loosely, which may refer to a class or an instance.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 3/39
12/21/2019 Object-oriented Programming (OOP) in C++
In other words, a class encapsulates the static attributes (data) and dynamic
behaviors (operations that operate on the data) in a box.
The following figure shows two instances of the class Student, identified as "paul" and "peter".
Unified Modeling Language (UML) Class and Instance Diagrams: The above class diagrams are drawn
according to the UML notations. A class is represented as a 3-compartment box, containing name, data members
(variables), and member functions, respectively. classname is shown in bold and centralized. An instance (object) is also
represented as a 3-compartment box, with instance name shown as instanceName:Classname and underlined.
Brief Summar y
1. A class is a programmer-defined, abstract, self-contained, reusable software entity that mimics a real-world thing.
2. A class is a 3-compartment box containing the name, data members (variables) and the member functions.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 4/39
12/21/2019 Object-oriented Programming (OOP) in C++
3. A class encapsulates the data structures (in data members) and algorithms (member functions). The values of the
data members constitute its state. The member functions constitute its behaviors.
4. An instance is an instantiation (or realization) of a particular item of a class.
2.3 Class Definition
In C++, we use the keyword class to define a class. There are two sections in the class declaration: private and public,
which will be explained later. For examples,
Class Naming Convention: A classname shall be a noun or a noun phrase made up of several words. All the words
shall be initial-capitalized (camel-case). Use a singular noun for classname. Choose a meaningful and self-descriptive
classname. For examples, SoccerPlayer, HttpProxyServer, FileInputStream, PrintStream and SocketFactory.
For examples, suppose that we have a class called Circle, we can create instances of Circle as follows:
Alternatively, you can invoke the constructor explicitly using the following syntax:
For example, suppose that we have a class called Circle, with two data members (radius and color) and two functions
(getRadius() and getArea()). We have created three instances of the class Circle, namely, c1, c2 and c3. To invoke
the function getArea(), you must first identity the instance of interest, says c2, then use the dot operator, in the form of
c2.getArea(), to invoke the getArea() function of instance c2.
For example,
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 5/39
12/21/2019 Object-oriented Programming (OOP) in C++
Calling getArea() without identifying the instance is meaningless, as the radius is unknown (there could be many
instances of Circle - each maintaining its own radius).
In general, suppose there is a class called AClass with a data member called aData and a member function called
aFunction(). An instance called anInstance is constructed for AClass. You use anInstance.aData and
anInstance.aFunction().
Data Member Naming Convention: A data member name shall be a noun or a noun phrase made up of several
words. The first word is in lowercase and the rest of the words are initial-capitalized (camel-case), e.g., fontSize,
roomNumber, xMax, yMin and xTopLeft. Take note that variable name begins with an lowercase, while classname begins
with an uppercase.
2.7 Member Functions
A member function (as described in the earlier chapter):
1. receives parameters from the caller,
2. performs the operations defined in the function body, and
3. returns a piece of result (or void) to the caller.
Member Function Naming Convention: A function name shall be a verb, or a verb phrase made up of several
words. The first word is in lowercase and the rest of the words are initial-capitalized (camel-case). For example,
getRadius(), getParameterValues().
Take note that data member name is a noun (denoting a static attribute), while function name is a verb (denoting an
action). They have the same naming convention. Nevertheless, you can easily distinguish them from the context.
Functions take arguments in parentheses (possibly zero argument with empty parentheses), but variables do not. In this
writing, functions are denoted with a pair of parentheses, e.g., println(), getArea() for clarity.
Three instances of Circles called c1, c2, and c3 shall then be constructed with their respective data members, as shown
in the instance diagrams.
In this example, we shall keep all the codes in a single source file called CircleAIO.cpp.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 6/39
12/21/2019 Object-oriented Programming (OOP) in C++
CircleAIO.cpp
1 /* The Circle class (All source codes in one file) (CircleAIO.cpp) */
2 #include <iostream> // using IO functions
3 #include <string> // using string
4 using namespace std;
5
6 class Circle {
7 private:
8 double radius; // Data member (Variable)
9 string color; // Data member (Variable)
10
11 public:
12 // Constructor with default values for data members
13 Circle(double r = 1.0, string c = "red") {
14 radius = r;
15 color = c;
16 }
17
18 double getRadius() { // Member function (Getter)
19 return radius;
20 }
21
22 string getColor() { // Member function (Getter)
23 return color;
24 }
25
26 double getArea() { // Member function
27 return radius*radius*3.1416;
28 }
29 }; // need to end the class declaration with a semi-colon
30
31 // Test driver function
32 int main() {
33 // Construct a Circle instance
34 Circle c1(1.2, "blue");
35 cout << "Radius=" << c1.getRadius() << " Area=" << c1.getArea()
36 << " Color=" << c1.getColor() << endl;
37
38 // Construct another Circle instance
39 Circle c2(3.4); // default color
40 cout << "Radius=" << c2.getRadius() << " Area=" << c2.getArea()
41 << " Color=" << c2.getColor() << endl;
42
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 7/39
12/21/2019 Object-oriented Programming (OOP) in C++
43 // Construct a Circle instance using default no-arg constructor
44 Circle c3; // default radius and color
45 cout << "Radius=" << c3.getRadius() << " Area=" << c3.getArea()
46 << " Color=" << c3.getColor() << endl;
47 return 0;
48 }
To compile and run the program (with GNU GCC under Windows):
> CircleAIO
Radius=1.2 Area=4.5239 Color=blue
Radius=3.4 Area=36.3169 Color=red
Radius=1 Area=3.1416 Color=red
2.9 Constructors
A constructor is a special function that has the function name same as the classname. In the above Circle class, we define
a constructor as follows:
A constructor is used to construct and initialize all the data members. To create a new instance of a class, you need to
declare the name of the instance and invoke the constructor. For example,
2. private: The member (data or function) is accessible and available within this class only.
For example, in the above Circle definition, the data member radius is declared private. As the result, radius is
accessible inside the Circle class, but NOT outside the class. In other words, you cannot use "c1.radius" to refer to
c1's radius in main(). Try inserting the statement "cout << c1.radius;" in main() and observe the error message:
Try moving radius to the public section, and re-run the statement.
On the other hand, the function getRadius() is declared public in the Circle class. Hence, it can be invoked in the
main().
UML Notation: In UML notation, public members are denoted with a "+", while private members with a "-" in the
class diagram.
Data member of a class are typically hidden from the outside word, with private access control modifier. Access to the
private data members are provided via public assessor functions, e.g., getRadius() and getColor().
This follows the principle of information hiding. That is, objects communicate with each others using well-defined
interfaces (public functions). Objects are not allowed to know the implementation details of others. The implementation
details are hidden or encapsulated within the class. Information hiding facilitates reuse of the class.
Rule of Thumb: Do not make any data member public, unless you have a good reason.
To allow other classes to modify the value of a private data member says xxx, you shall provide a set function (or setter
or mutator function) called setXxx(). A setter could provide data validation (such as range checking), and transform the
raw data into the internal representation.
For example, in our Circle class, the data members radius and color are declared private. That is to say, they are
only available within the Circle class and not visible outside the Circle class - including main(). You cannot access the
private data members radius and color from the main() directly - via says c1.radius or c1.color. The Circle class
provides two public accessor functions, namely, getRadius() and getColor(). These functions are declared public. The
main() can invoke these public accessor functions to retrieve the radius and color of a Circle object, via says
c1.getRadius() and c1.getColor().
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 9/39
12/21/2019 Object-oriented Programming (OOP) in C++
There is no way you can change the radius or color of a Circle object, after it is constructed in main(). You cannot
issue statements such as c1.radius = 5.0 to change the radius of instance c1, as radius is declared as private in
the Circle class and is not visible to other including main().
If the designer of the Circle class permits the change the radius and color after a Circle object is constructed, he has
to provide the appropriate setter, e.g.,
With proper implementation of information hiding, the designer of a class has full control of what the user of the class can
and cannot do.
2.14 Keyword "this"
You can use keyword "this" to refer to this instance inside a class definition.
One of the main usage of keyword this is to resolve ambiguity between the names of data member and function
parameter. For example,
class Circle {
private:
double radius; // Member variable called "radius"
......
public:
void setRadius(double radius) { // Function's argument also called "radius"
this->radius = radius;
// "this.radius" refers to this instance's member variable
// "radius" resolved to the function's argument.
}
......
}
In the above codes, there are two identifiers called radius - a data member and the function parameter. This causes
naming conflict. To resolve the naming conflict, you could name the function parameter r instead of radius. However,
radius is more approximate and meaningful in this context. You can use keyword this to resolve this naming conflict.
"this->radius" refers to the data member; while "radius" resolves to the function parameter.
"this" is actually a pointer to this object. I will explain pointer and the meaning of "->" operator later.
Alternatively, you could use a prefix (such as m_) or suffix (such as _) to name the data members to avoid name crashes.
For example,
class Circle {
private:
double m_radius; // or radius_
......
public:
void setRadius(double radius) {
m_radius = radius; // or radius_ = radius
}
......
}
C++ Compiler internally names their data members beginning with a leading underscore (e.g., _xxx) and local
variables with 2 leading underscores (e.g., __xxx). Hence, avoid name beginning with underscore in your program.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 10/39
12/21/2019 Object-oriented Programming (OOP) in C++
A const member function, identified by a const keyword at the end of the member function's header, cannot modifies
any data member of this object. For example,
class Aaa {
private:
// A private variable named xxx of type T
T xxx;
public:
// Constructor
Aaa(T x) { xxx = x; }
// OR
Aaa(T xxx) { this->xxx = xxx; }
// OR using member initializer list (to be explained later)
Aaa(T xxx) : xxx(xxx) { }
// A getter for variable xxx of type T receives no argument and return a value of type T
T getXxx() const { return xxx; }
// A setter for variable xxx of type T receives a parameter of type T and return void
void setXxx(T x) { xxx = x; }
// OR
void setXxx(T xxx) { this->xxx = xxx; }
}
For a bool variable xxx, the getter shall be named isXxx(), instead of getXxx(), as follows:
private:
// Private boolean variable
bool xxx;
public:
// Getter
bool isXxx() const { return xxx; }
// Setter
void setXxx(bool x) { xxx = x; }
// OR
void setXxx(bool xxx) { this->xxx = xxx; }
2.17 Default Constructor
A default constructor is a constructor with no parameters, or having default values for all the parameters. For example, the
above Circle's constructor can be served as default constructor with all the parameters default.
Circle c1; // Declare c1 as an instance of Circle, and invoke the default constructor
Circle c1(); // Error!
// (This declares c1 as a function that takes no parameter and returns a Circle instance)
If C++, if you did not provide ANY constructor, the compiler automatically provides a default constructor that does
nothing. That is,
Compiler will not provide a default constructor if you define any constructor(s). If all the constructors you defined require
arguments, invoking no-argument default constructor results in error. This is to allow class designer to make it impossible
to create an uninitialized instance, by NOT providing an explicit default constructor.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 11/39
12/21/2019 Object-oriented Programming (OOP) in C++
Member initializer list is placed after the constructor's header, separated by a colon (:). Each initializer is in the form of
data_member_name(parameter_name). For fundamental type, it is equivalent to data_member_name =
parameter_name. For object, the constructor will be invoked to construct the object. The constructor's body (empty in
this case) will be run after the completion of member initializer list.
It is recommended to use member initializer list to initialize all the data members, as it is often more efficient than doing
assignment inside the constructor's body.
2.19 *Destructor
A destructor, similar to constructor, is a special function that has the same name as the classname, with a prefix ~, e.g.,
~Circle(). Destructor is called implicitly when an object is destroyed.
If you do not define a destructor, the compiler provides a default, which does nothing.
class MyClass {
public:
// The default destructor that does nothing
~MyClass() { }
......
}
Advanced Notes
If your class contains data member which is dynamically allocated (via new or new[] operator), you need to free the
storage via delete or delete[].
2.20 *Copy Constructor
A copy constructor constructs a new object by copying an existing object of the same type. In other words, a copy
constructor takes an argument, which is an object of the same class.
If you do not define a copy constructor, the compiler provides a default which copies all the data members of the given
object. For example,
The copy constructor is particularly important. When an object is passed into a function by value, the copy constructor will
be used to make a clone copy of the argument.
Advanced Notes
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 12/39
12/21/2019 Object-oriented Programming (OOP) in C++
Pass-by-value for object means calling the copy constructor. To avoid the overhead of creating a clone copy, it is
usually better to pass-by-reference-to-const, which will not have side effect on modifying the caller's object.
class MyClass {
private:
T1 member1;
T2 member2;
public:
// The default copy constructor which constructs an object via memberwise copy
MyClass(const MyClass & rhs) {
member1 = rhs.member1;
member2 = rhs.member2;
}
......
}
The default copy constructor performs shadow copy. It does not copy the dynamically allocated data members
created via new or new[] operator.
Advanced Notes
You could overload the assignment opeator to override the default.
The copy constructor, instead of copy assignment operator, is used in declaration:
Circle c8 = c6; // Invoke the copy constructor, NOT copy assignment operator
// Same as Circle c8(c6)
The default copy assignment operator performs shadow copy. It does not copy the dynamically allocated data
members created via new or new[] operator.
class MyClass {
private:
T1 member1;
T2 member2;
public:
// The default copy assignment operator which assigns an object via memberwise copy
MyClass & operator=(const MyClass & rhs) {
member1 = rhs.member1;
member2 = rhs.member2;
return *this;
}
......
}
The copy assignment operator differs from the copy constructor in that it must release the dynamically allocated
contents of the target and prevent self assignment. The assignment operator shall return a reference of this object to
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 13/39
12/21/2019 Object-oriented Programming (OOP) in C++
The default constructor, default destructor, default copy constructor, default copy assignment operators are known as
special member functions, in which the compiler will automatically generate a copy if they are used in the program
and not explicitly defined.
Circle.h - Header
1 /* The Circle class Header (Circle.h) */
2 #include <string> // using string
3 using namespace std;
4
5 // Circle class declaration
6 class Circle {
7 private: // Accessible by members of this class only
8 // private data members (variables)
9 double radius;
10 string color;
11
12 public: // Accessible by ALL
13 // Declare prototype of member functions
14 // Constructor with default values
15 Circle(double radius = 1.0, string color = "red");
16
17 // Public getters & setters for private data members
18 double getRadius() const;
19 void setRadius(double radius);
20 string getColor() const;
21 void setColor(string color);
22
23 // Public member Function
24 double getArea() const;
25 };
Program Notes:
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 14/39
12/21/2019 Object-oriented Programming (OOP) in C++
The header file contains declaration statements, that tell the compiler about the names and types, and function
prototypes without the implementation details.
C++98/03 does NOT allow you to assign an initial value to a data member (except const static members). Date
members are to be initialized via the constructor. For example,
Header contains function prototype, the parameter names are ignored by the compiler, but good to serve as
documentation. For example, you can leave out the parameter names in the prototype as follows:
Circle.cpp - Implementation
1 /* The Circle class Implementation (Circle.cpp) */
2 #include "Circle.h" // user-defined header in the same directory
3
4 // Constructor
5 // default values shall only be specified in the declaration,
6 // cannot be repeated in definition
7 Circle::Circle(double r, string c) {
8 radius = r;
9 color = c;
10 }
11
12 // Public getter for private data member radius
13 double Circle::getRadius() const {
14 return radius;
15 }
16
17 // Public setter for private data member radius
18 void Circle::setRadius(double r) {
19 radius = r;
20 }
21
22 // Public getter for private data member color
23 string Circle::getColor() const {
24 return color;
25 }
26
27 // Public setter for private data member color
28 void Circle::setColor(string c) {
29 color = c;
30 }
31
32 // A public member function
33 double Circle::getArea() const {
34 return radius*radius*3.14159265;
35 }
Program Notes:
The implementation file provides the definition of the functions, which are omitted from the declaration in the header
file.
#include "Circle.h"
The compiler searches the headers in double quotes (such as "Circle.h") in the current directory first, then the
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 15/39
12/21/2019 Object-oriented Programming (OOP) in C++
system's include directories. For header in angle bracket (such as <iostream>), the compiler does NOT searches the
current directory, but only the system's include directories. Hence, use double quotes for user-defined headers.
Circle::Circle(double r, string c) {
You need to include the className:: (called class scope resolution operator) in front of all the members names, so as
to inform the compiler this member belong to a particular class.
(Class Scope: Names defined inside a class have so-called class scope. They are visible within the class only. Hence,
you can use the same name in two different classes. To use these names outside the class, the class scope resolution
operator className:: is needed.)
You CANNOT place the default arguments in the implementation (they shall be placed in the header). For example,
To use the Circle class, the user needs Circle.h and Circle.o. He does not need Circle.cpp. In other words, you do
not need to give away your source codes, but merely the public declarations and the object codes.
You can also compile TestCircle.cpp with the source code Circle.cpp (and Circle.h)
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 16/39
12/21/2019 Object-oriented Programming (OOP) in C++
Let's write the code for the Time class, with the header and implementation separated in two files: Time.h and Time.cpp.
Header - Time.h
1 /* Header for the Time class (Time.h) */
2 #ifndef TIME_H // Include this "block" only if TIME_H is NOT defined
3 #define TIME_H // Upon the first inclusion, define TIME_H so that
4 // this header will not get included more than once
5 class Time {
6 private: // private section
7 // private data members
8 int hour; // 0 - 23
9 int minute; // 0 - 59
10 int second; // 0 - 59
11
12 public: // public section
13 // public member function prototypes
14 Time(int h = 0, int m = 0, int s = 0); // Constructor with default values
15 int getHour() const; // public getter for private data member hour
16 void setHour(int h); // public setter for private data member hour
17 int getMinute() const; // public getter for private data member minute
18 void setMinute(int m); // public setter for private data member minute
19 int getSecond() const; // public getter for private data member second
20 void setSecond(int s); // public setter for private data member second
21 void setTime(int h, int m, int s); // set hour, minute and second
22 void print() const; // Print a description of this instance in "hh:mm:ss"
23 void nextSecond(); // Increase this instance by one second
24 }; // need to terminate the class declaration with a semicolon
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 17/39
12/21/2019 Object-oriented Programming (OOP) in C++
25
26 #endif // end of "#ifndef" block
Dissecting Time.h
#ifndef TIME_H
#define TIME_H
......
#endif
To prevent an header file from included more than once into a source file (which could result in compilation error if an
entity is declared twice, e.g., int i), we wrap the header codes within a pair of preprocessor directives #ifndef (if not
define) and #endif. The codes within the if-block will only be included if the identifier TIME_H has not been defined. This
is true for the first inclusion, which also defines the identifier TIME_H (the first directive in body of the if-block). No
subsequent inclusion is possible, since TIME_H has been defined during the first inclusion. By convention, use the
identifier XXX_H (or XXX_H_INCLUDED) for header Xxx.h.
class Time {
private:
......
public:
......
};
The header Time.h contains the class declaration for the class Time. It is divided into two sections: private and public.
The private members (data or functions) are accessible by members of this class only, while public members are visible
by all (such as the main() function which is outside the class). The class declaration must be terminated by a semicolon.
private:
int hour;
int minute;
int second;
public:
......
We declare 3 private data members called hour, minute and second. In C++98/C++03, you are NOT allow to initialize a
data member in the class declaration (except const static int data members). For example, setting hour = 0 causes a
compilation error. Instead, the data members are to be initialized in the constructor (to be shown later). The newer C++11
allows initialization of data members.
Only member function prototypes are listed in the class declaration. A function prototype consists of the return-type,
function name and parameter types.
In the function prototypes of the header, we can set the default values of the function's parameters for any function
member using "= default-value". In this case, this constructor can be invoked with 0 to 3 arguments, the omitted
trailing arguments will be set to their default values, e.g.,
The identifiers h, m and s are not needed in the function prototype - you only need to specify the parameters' types. But
they serve as proper documentation, and are strongly recommended.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 18/39
12/21/2019 Object-oriented Programming (OOP) in C++
void nextSecond();
declares a public member function to increase this instance by one second. For example, 23:59:59 becomes 00:00:00.
The function nextSecond() returns void.
Implementation - Time.cpp
1 /* Implementation for the Time Class (Time.cpp) */
2 #include <iostream>
3 #include <iomanip>
4 #include "Time.h" // include header of Time class
5 using namespace std;
6
7 // Constructor with default values. No input validation
8 Time::Time(int h, int m, int s) {
9 hour = h;
10 minute = m;
11 second = s;
12 }
13
14 // public getter for private data member hour
15 int Time::getHour() const {
16 return hour;
17 }
18
19 // public setter for private data member hour. No input validation
20 void Time::setHour(int h) {
21 hour = h;
22 }
23
24 // public getter for private data member minute
25 int Time::getMinute() const {
26 return minute;
27 }
28
29 // public setter for private data member minute. No input validation
30 void Time::setMinute(int m) {
31 minute = m;
32 }
33
34 // public getter for private data member second
35 int Time::getSecond() const {
36 return second;
37 }
38
39 // public setter for private data member second. No input validation
40 void Time::setSecond(int s) {
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 19/39
12/21/2019 Object-oriented Programming (OOP) in C++
41 second = s;
42 }
43
44 // Set hour, minute and second. No input validation
45 void Time::setTime(int h, int m, int s) {
46 hour = h;
47 minute = m;
48 second = s;
49 }
50
51 // Print this Time instance in the format of "hh:mm:ss", zero filled
52 void Time::print() const {
53 cout << setfill('0'); // zero-filled, need <iomanip>, sticky
54 cout << setw(2) << hour // set width to 2 spaces, need <iomanip>, non-sticky
55 << ":" << setw(2) << minute
56 << ":" << setw(2) << second << endl;
57 }
58
59 // Increase this instance by one second
60 void Time::nextSecond() {
61 ++second;
62 if (second >= 60) {
63 second = 0;
64 ++minute;
65 }
66 if (minute >= 60) {
67 minute = 0;
68 ++hour;
69 }
70 if (hour >= 24) {
71 hour = 0;
72 }
73 }
Dissecting Time.cpp
The implementation file Time.cpp contains member's definitions (whereas the header file contains the declarations), in
particular, member functions.
All member's identifiers in the implementation are preceded by the classname and the scope resolution operator (::), e.g.,
Time::Time and Time::getHour, so that the compiler can tell that these identifiers belong to a particular class, in this
case, Time.
The default values of the parameters are specified in the class declaration (in the header), NOT in the function definition.
Placing a default value in function definition (e.g., h = 0) causes a compilation error.
Take note that we have not included input validation (e.g., hour shall be between 0 and 23) in the constructor (and
setters). We shall do that in the later example.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 20/39
12/21/2019 Object-oriented Programming (OOP) in C++
void Time::setHour(int h) {
hour = h;
}
the public setter for private data member hour sets the data member hour to the given value h. Again, there is no input
validation for h (shall be between 0 to 23).
"this" Pointer
Instead of naming the function parameters h, m and s, we would like to name the parameters hour, minute and second,
which are semantically more meaningful. However, these names crashes with the names of private data members. C++
provides a keyword this (which is a pointer to this instance - to be discussed later) to differentiate between the data
members and function parameters. this->hour, this->minute and this->second refer to the data members; while
hour, minute, and second refer to the function parameters. We can rewrite the constructor and setter as follows:
The member initializer list is placed after the function parameter list, separated by a colon, in the form of
dataMemberName(parameters). For fundamental-type data members (e.g., int, double), hour(h) is the same as hour
= h. For object data members (to be discussed later), the copy constructor will be invoked. The function body will be
executed after the member initializer list, which is empty in this case.
The data members in the initializer list are initialized in the order of their declarations in the class declaration, not the
order in the initializer list.
Dissecting TestTime.cpp
The test driver tests the constructor (with and without the default values) and all the public member functions. Clearly, no
input validation is carried out, as reflected in instance t5.
Exercise
Add member functions previousSecond(), nextMinute(), previousMinute(), nextHour(), previousHour() to the
Time class.
Alternatively, you can compile Time.cpp into an object file Time.o, and then the test driver with the object file. In this
way, you only distribute the object file and header file, not the source file.
In the class diagram, "-" denotes private member; "+" denotes public member. "= xxx" specifies the default value of a
data member.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 22/39
12/21/2019 Object-oriented Programming (OOP) in C++
Point.h - Header
1 /* The Point class Header (Point.h) */
2 #ifndef POINT_H
3 #define POINT_H
4
5 // Point class declaration
6 class Point {
7 private:
8 // private data members (variables)
9 int x;
10 int y;
11
12 public:
13 // Declare member function prototypes
14 Point(int x = 0, int y = 0); // Constructor with default values
15 int getX() const;
16 void setX(int x);
17 int getY() const;
18 void setY(int y);
19 void setXY(int x, int y);
20 double getMagnitude() const;
21 double getArgument() const;
22 void print() const;
23 };
24
25 #endif
Point.cpp - Implementation
1 /* The Point class Implementation (Point.cpp) */
2 #include "Point.h" // user-defined header in the same directory
3 #include <iostream>
4 #include <cmath>
5 using namespace std;
6
7 // Constructor (default values can only be specified in the declaration)
8 Point::Point(int x, int y) : x(x), y(y) { } // Use member initializer list
9
10 // Public getter for private data member x
11 int Point::getX() const {
12 return x;
13 }
14
15 // Public setter for private data member x
16 void Point::setX(int x) {
17 this->x = x;
18 }
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 23/39
12/21/2019 Object-oriented Programming (OOP) in C++
19
20 // Public getter for private data member y
21 int Point::getY() const {
22 return y;
23 }
24
25 // Public setter for private data member y
26 void Point::setY(int y) {
27 this->y = y;
28 }
29
30 // Public member function to set both x and y
31 void Point::setXY(int x, int y) {
32 this->x = x;
33 this->y = y;
34 }
35
36 // Public member function to return the magitude
37 double Point::getMagnitude() const {
38 return sqrt(x*x + y*y); // sqrt in <cmath>
39 }
40
41 // Public member function to return the argument
42 double Point::getArgument() const {
43 return atan2(y, x); // atan2 in <cmath>
44 }
45
46 // Public member function to print description about this point
47 void Point::print() const {
48 cout << "(" << x << "," << y << ")" << endl;
49 }
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 24/39
12/21/2019 Object-oriented Programming (OOP) in C++
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 25/39
12/21/2019 Object-oriented Programming (OOP) in C++
22 balance = b;
23 }
24
25 // Adds the given amount to the balance
26 void Account::credit(double amount) {
27 balance += amount;
28 }
29
30 // Subtract the given amount from the balance
31 void Account::debit(double amount) {
32 if (amount <= balance) {
33 balance -= amount;
34 } else {
35 cout << "Amount withdrawn exceeds the current balance!" << endl;
36 }
37 }
38
39 // Print description for this Account instance
40 void Account::print() const {
41 cout << fixed << setprecision(2);
42 cout << "A/C no: " << accountNumber << " Balance=$" << balance << endl;
43 }
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 26/39
12/21/2019 Object-oriented Programming (OOP) in C++
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 28/39
12/21/2019 Object-oriented Programming (OOP) in C++
12 ball.setX(5.5);
13 ball.setY(6.6);
14 cout << "x is " << ball.getX() << endl; // x is 5.50
15 cout << "y is " << ball.getY() << endl; // y is 6.60
16 ball.move();
17 ball.print(); // Ball @ (8.80,11.00) with speed (3.30,4.40)
18 }
A constructor to
initialize the name,
email and gender with
the given values. There
are no default values
for data members.
Getters for name, email
and gender, and setter
for email. There is no
setter for name and
gender as we assume
that these attributes
cannot be changed.
A print() member
function that prints
"name (gender) at
email", e.g., "Peter
Jones (m) at
peter@somewhere.com
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 30/39
12/21/2019 Object-oriented Programming (OOP) in C++
To differentiate between the two identifiers, we use the keyword this, which is a pointer to this instance. this->name
refers to the data member; while name refers to the function's parameter.
No input validation is done on the parameter name. On the other hand, for email, we invoke setter setEmail() which
performs input validation.
TestAuthor.cpp
1 /* Test Driver for the Author class (TestAuthor.cpp) */
2 #include "Author.h"
3
4 int main() {
5 // Declare and construct an instance of Author
6 Author peter("Peter Jones", "peter@somewhere.com", 'm');
7 peter.print();
8 // Peter Jones (m) at peter@somewhere.com
9 peter.setEmail("peter@xyz.com");
10 peter.print();
11 // Peter Jones (m) at peter@xyz.com
12
13 Author paul("Paul Jones", "@somewhere.com", 'n');
14 // Invalid email! Set to empty string.
15 // Invalid gender! Set to 'u' (unknown).
16 paul.setEmail("paul@");
17 // Invalid email! Set to empty string.
18 paul.print();
19 // Paul Jones (u) at
20 }
The hallow diamond shape in the class diagram denotes aggregation (or has-a) association relationship. That is, a Book
instance has one (and only one) Author instance as its component.
#include "Author.h"
We need to include the "Author.h" header, as we use the Author class in this class Book.
private:
Author author;
We declare a private data member author as an instance of class Author, defined earlier.
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 33/39
12/21/2019 Object-oriented Programming (OOP) in C++
41 // Validate qtyInStock, which cannot be negative
42 void Book::setQtyInStock(int qtyInStock) {
43 if (qtyInStock >= 0) {
44 this->qtyInStock = qtyInStock;
45 } else {
46 cout << "qtyInStock cannot be negative! Set to 0" << endl;
47 this->qtyInStock = 0;
48 }
49 }
50
51 // print in the format ""Book-name" by author-name (gender) at email"
52 void Book::print() const {
53 cout << "'" << name << "' by ";
54 author.print();
55 }
56
57 // Return the author' name for this Book
58 string Book::getAuthorName() const {
59 return author.getName(); // invoke the getName() on instance author
60 }
TestBook.cpp
1 /* Test Driver for the Book class (TestBook.cpp) */
2 #include <iostream>
3 #include "Book.h"
4 using namespace std;
5
6 int main() {
7 // Declare and construct an instance of Author
8 Author peter("Peter Jones", "peter@somewhere.com", 'm');
9 peter.print(); // Peter Jones (m) at peter@somewhere.com
10
11 // Declare and construct an instance of Book
12 Book cppDummy("C++ for Dummies", peter, 19.99);
13 cppDummy.setQtyInStock(88);
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 34/39
12/21/2019 Object-oriented Programming (OOP) in C++
14 cppDummy.print();
15 // 'C++ for Dummies' by Peter Jones (m) at peter@somewhere.com
16
17 cout << cppDummy.getQtyInStock() << endl; // 88
18 cout << cppDummy.getPrice() << endl; // 19.99
19 cout << cppDummy.getAuthor().getName() << endl; // "Peter Jones"
20 cout << cppDummy.getAuthor().getEmail() << endl; // "peter@somewhere.com"
21 cout << cppDummy.getAuthorName() << endl; // "Peter Jones"
22
23 Book moreCpp("More C++ for Dummies", peter, -19.99);
24 // price should be positive! Set to 0
25 cout << moreCpp.getPrice() << endl; // 0
26 }
Instead, we could pass an object into function by reference, via the reference (&) declaration in the parameter list. If we do
not intend to modify the object inside the function (with side effect to the original copy), we set it as const.
In the Book class, data members of string and Author are objects. Author class was defined earlier; string is a class
provided in C++ header <string>, belonging to the namespace std. Instead of including "using namespace std;" in
the header (which is a poor practice as this statement will be included in all the files using this header), we shall use the
scope resolution operator and refer to it as std::string.
Author.h
1 /* Header for Author class (Author.h) */
2 #ifndef AUTHOR_H
3 #define AUTHOR_H
4
5 #include <string>
6
7 class Author {
8 private:
9 std::string name;
10 std::string email;
11 char gender; // 'm', 'f', or 'u' for unknown
12
13 public:
14 Author(const std::string & name, const std::string & email, char gender);
15 // & specifies pass by reference, const for non-mutable
16 std::string getName() const;
17 std::string getEmail() const;
18 void setEmail(const std::string & email);
19 char getGender() const;
20 void print() const;
21 };
22
23 #endif
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 35/39
12/21/2019 Object-oriented Programming (OOP) in C++
Program Notes:
In C++, string is a class in the standard library (in header <string>, belonging to namespace std), just like Point,
Circle classes that we have defined.
Instead of including "using namespace std;", which is a poor practice as this statement will be included in all the
files using this header, we use the fully-qualified name std::string.
Instead of passing string objects by value into function, which affects performance as a clone copy needs to be
made. We pass the string objects by reference (indicated by &).
However, in pass-by-reference, changes inside the function will affect the caller's copy outside the function.
If we do not intend to change the object inside the function, we could use keyword const to indicate immutability. If
the object is inadvertently changed inside the function, compiler would issue an error.
Author.cpp
1 /* Implementation for the Author class (Author.cpp) */
2 #include <iostream>
3 #include "Author.h"
4 using namespace std;
5
6 // Constructor, with input validation
7 Author::Author(const string & name, const string & email, char gender) : name(name) {
8 setEmail(email); // Call setter to check for valid email
9 if (gender == 'm' || gender == 'f') {
10 this->gender = gender;
11 } else {
12 cout << "Invalid gender! Set to 'u' (unknown)." << endl;
13 this->gender = 'u';
14 }
15 }
16
17 string Author::getName() const {
18 return name;
19 }
20
21 string Author::getEmail() const {
22 return email;
23 }
24
25 void Author::setEmail(const string & email) {
26 // Check for valid email. Assume that a valid email contains
27 // a '@' that is not the first nor last character.
28 size_t atIndex = email.find('@');
29 if (atIndex != string::npos && atIndex != 0 && atIndex != email.length()-1) {
30 this->email = email;
31 } else {
32 cout << "Invalid email! Set to empty string." << endl;
33 this->email = "";
34 }
35 }
36
37 char Author::getGender() const {
38 return gender;
39 }
40
41 // print in the format "name (gender) at email"
42 void Author::print() const {
43 cout << name << " (" << gender << ") at " << email << endl;
44 }
Program Notes:
Author::Author(const string & name, const string & email, char gender) { ...... }
In the constructor, the string objects are passed by reference. This improves the performance as it eliminates the
need of creating a temporary (clone) object. The constructor then invokes the copy constructor of the string class to
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 36/39
12/21/2019 Object-oriented Programming (OOP) in C++
memberwise copy the arguments into its data members name and email.
We make the parameters const to prevent them from modifying inside the function (with side effect to the original
copies).
Book.h
1 /* Header for the class Book (Book.h) */
2 #ifndef BOOK_H
3 #define BOOK_H
4
5 #include <string>
6 #include "Author.h" // Use the Author class
7 using namespace std;
8
9 class Book {
10 private:
11 string name;
12 Author author;
13 double price;
14 int qtyInStock;
15
16 public:
17 Book(const string & name, const Author & author, double price, int qtyInStock = 0);
18 string getName() const;
19 Author getAuthor() const;
20 double getPrice() const;
21 void setPrice(double price);
22 int getQtyInStock() const;
23 void setQtyInStock(int qtyInStock);
24 void print() const;
25 string getAuthorName() const;
26 };
27
28 #endif
Program Notes:
Book(const string & name, const Author & author, double price, int qtyInStock = 0);
string and Author objects are passed into the constructor via reference. This improves performance as it eliminates
the creation of a temporary clone copy in pass-by-value. The parameters are marked const as we do not intend to
modify them inside the function (with side effect to the original copies).
Author getAuthor() const;
The getter returns a copy of the data member author.
Book.cpp
1 /* Implementation for the class Book (Book.cpp) */
2 #include <iostream>
3 #include "Book.h"
4 using namespace std;
5
6 // Constructor, with member initializer list to initialize the
7 // component Author instance
8 Book::Book(const string & name, const Author & author, double price, int qtyInStock)
9 : name(name), author(author) { // Init object reference in member initializer list
10 // Call setters to validate price and qtyInStock
11 setPrice(price);
12 setQtyInStock(qtyInStock);
13 }
14
15 string Book::getName() const {
16 return name;
17 }
18
19 Author Book::getAuthor() {
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 37/39
12/21/2019 Object-oriented Programming (OOP) in C++
20 return author;
21 }
22
23 double Book::getPrice() const {
24 return price;
25 }
26
27 // Validate price, which shall be positive
28 void Book::setPrice(double price) {
29 if (price > 0) {
30 this->price = price;
31 } else {
32 cout << "price should be positive! Set to 0" << endl;
33 this->price = 0;
34 }
35 }
36
37 int Book::getQtyInStock() const {
38 return qtyInStock;
39 }
40
41 // Validate qtyInStock, which cannot be negative
42 void Book::setQtyInStock(int qtyInStock) {
43 if (qtyInStock >= 0) {
44 this->qtyInStock = qtyInStock;
45 } else {
46 cout << "qtyInStock cannnot be negative! Set to 0" << endl;
47 this->qtyInStock = 0;
48 }
49 }
50
51 // print in the format ""Book-name" by author-name (gender) at email"
52 void Book::print() const {
53 cout << "'" << name << "' by ";
54 author.print();
55 }
56
57 // Return the author' name for this Book
58 string Book::getAuthorName() const {
59 return author.getName(); // invoke the getName() on instance author
60 }
Book::Book(const string & name, Author & author, double price, int qtyInStock)
: name(name), author(author) { ...... }
name(name) and author(author) invoke the default copy constructors to construct new instances of string and
Author by memberwise copy the parameters.
In the above test program, an instance of Author called peter is constructed (in Line 8). This instance is passed by
reference into Book's constructor (Line 12) to create the Book's instance cppDummy.
Summar y
All the codes in this version of example (using references) is exactly the same as the previous version (without using
references), except that the object function parameters are marked with "const classname &" (e.g., const string &,
const Author &). This eliminates the creation of temporary clone object as in the pass-by-value, which improves the
performance. Take note that the constructor actually invokes the copy constructor to make a copy for its data member,
instead of referencing the copy provided by the caller.
Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan (ehchua@ntu.edu.sg) | HOME
https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp3_OOP.html#zz-9.3 39/39