Introduction & Review

Introduction To Object Oriented Programming

For the most part in C++ Level 1 you learned procedural level programming. This style of programming is very linear. In fact, in most instances you could write a list of tasks, then take that list and turn it into code, one task item at a time. This is very much how a flow chart would work. Consider the following flowchart for printing employees paychecks:

This type of programming is also called functional decomposition or stepwise refinement. This is where each of the tasks that need to be performed can be broken down into separate functions. Functional composition can then be illustrated using the following organizational chart:

Probably the biggest problem with the above type of organization is that there is no prevision to bundle data and functionality together. Having data bundled with its operations makes the code more cohesive. It also allows for a better way of performing a task.

In objected oriented programming, or OOP, you would probably construct an object called PayrollPrinter that would bring together all of the functionality found in the organizational chart above. You can think of objects in OOP as self contained entities. That is, they contain all of the variables and functionality needed to perform the task. This is depicted in the following UML class diagram:

Objects are made up of three characteristics:

  1. State
  2. Behavior
  3. Identity

State - The state of an object is identified by its attributes and the values they hold. Conceptually speaking if we had a lamp object we could say that its state is either on or off. The value of this state would be held in a variable that is part of the object itself.

Behavior - The behavior of an object is defined by the actions the object can perform. You might say it is the object's functionality. In the case of the lamp it can have a state of on or off but the behavior of the object is that you can turn it on or off. This means the lamp object has functionality to change the state of the lamp (on or off).

Identity - The identity of an object is typically the object's ID or name. A class is a fully formed type which means you can create many instances of it. Each instance of a class is an object. The instance name is the object's identity. Take for example a Lamp class: we can create many instances of Lamp like we would any other primitive data type.

int myInteger; // An instance of a primitive int called myInteger
Lamp myLamp; // An instance of a Lamp class called myLamp 

What Are Classes?

In OOP programs consist of cooperating objects that can relate with each other in different ways. So where does the class fit in all of this? Classes and objects are often confused by people. The truth is their difference is quite simple.

The class is the definition of what the object is. You could say that a class is a blueprint for an object.

An object then is nothing more than an instance of the class. Having stated this, we should probably review the definition of data types once more.

Primitive Data Types - Primitive data types are the data types that are built into the C++ language. You know them as things like:

  • int
  • char
  • float
  • double
  • bool

to name a few. You can create instances of a primitive very easily:

int x, y, z;

Above three instances of an int have been created. They are x, y, and z. This is something you saw early on in level 1 but you may not have remembered the terminology.

Complex Data Types - Complex data types are defined by the programmer and typically use primitive types in their construction. What this means is that a complex data type is a class that is created by the programmer. It is an encapsulation of data and functions.

As an example, if you have created a class called Lamp then you could create as many instances of it as you wish:

Lamp bedRoom, livingRoom;

Here two lamp objects have been created from the class Lamp. One called bedRoom and the other called livingRoom.

The class defines the characteristics of each individual object. It consists of attributes and functions.

As you begin writing C++ programs, you'll find that classes are very important. In your class definitions you describe the attributes that each of your objects possesses and define the functions that each uses to carry out its actions.

As you write your class definitions, you'll rely on three very important OOP principles: encapsulation, inheritance, and polymorphism.

Encapsulation & Data Hiding

As you've seen, in addition to having its own identity every object is divided into two parts: the things that it knows how to do, and the data the object contains. In a procedural program the procedures that make up the program and the data that those procedures operate on are separate. In an object-oriented program they are combined. This process of wrapping up procedures and data together is called encapsulation.

Encapsulation is used to enforce the principle of data hiding. With encapsulation, the attributes defined inside a class are accessible to all the functions within the same class but they cannot be accessed by methods outside of the class.

Before OOP if you had two functions that needed to operate on the same piece of information you had to either make the data publicly accessible or you had to pass the data as an argument to each of the functions that operated on it.

Having data publicly accessible (as global variables) runs the risk of accidentally corrupting the data. This can easily happen as a result of a bug in someone else's code. Passing the data as an argument is a better way for more than one function to have access to a piece of data but this process can be somewhat tedious and error prone.

Encapsulating data allows the functions written for the data to have direct access to it and provides protection from functionality outside of the class.

Inheritance & Code Reuse

Inheritance is another important OOP concept because it promotes the idea of code reuse. Once you have gone through the painstaking chore of designing, coding, and debugging a class it can then be used as a starting point for a new class. What this allows you to do is to create a specialized version of the class. As an example consider the Lamp class. The Lamp can be considered the generic class. It has a shape, a shade type, and a state. Suppose now we wanted to create a new Lamp type called WorkBenchLamp. This Lamp has all of the functionality of a regular lamp but it also has new features dim and swivel. To create this lamp you wouldn't simply start over and design the basic lamp functionality. Your best bet would be to start with the basic lamp and add the needed functionality to it. This is the idea behind inheritance. You can simply borrow code to create a specialized version of the class. As you will see using inheritance is an easy thing to do.

Interested In What Others Say About OOP?

Check out what LearnCPP has to say about Object Oriented Programming

Lecture Video

Lecture 0 Review & OOP
Lecture 0 Review & OOP

CStrings vs C++ String Class

The C++ language was born out of C which was meant to be a high level language that was close to assembly without having to write assembly. In fact, there are only 32 keywords in the "C" language (A language like Java on the other hand has 50). As a result of trying to keep the language low level there was never a facility for strings. The idea of a string in "C" was to simply use an array of characters and terminate it with NULL. When C++ came about these arrays of characters were simply called CStrings. Of course this led to a bunch of functions being added to the standard "C" library to handle the CString. You have probably used some of them. Here is a partial list:

  • strlen - returns the length of a CString
  • strcpy - copies one CString to another
  • strcmp - compares two strings. Returns 0 if they are equal
  • strcat - appends one string to the end of another

The string class is part of the Standard Template Library (STL) that was created by Andrew Koenig while working at Bell Labs and Hewlett Packard. The STL became part of the ANSI standard in 1993 and has been used since this time. The STL will be covered later on in greater detail but for now we are going to concentrate on the string class. 

Using an array for strings is efficient in terms of processing but for development they can be a little trying. The string class gives you much more flexibility because it has a great deal of functionality built into it. In addition, while it is a complex type it can be used very much like a primitive type. The following example shows how easy it is to create an instance of a string:

#include <iostream>
#include <string>

using namespace std;

int main()
    string s;
    cin >> s;
    cout << s << endl;

    return 0;

Accessing Characters

The string class in C++ can be used like an array. What this means is that you can use the subscript operator [] like you would with an array:

int main()
    string str;    
    str[0] = 'C';
    cout << str[0] << endl; // Prints the letter 'C'
    return 0;

It is interesting to note that when you add elements using the subscript operator memory gets allocated for the space if need be. For instance if you were to use cout with above example to output a different element of the string it would throw an error:

The above code attempts to print the second item in the string (index 1) but as you can see this index is out of range.

The at function gives you access to the individual elements of the string in the same way that the subscript operator does. The caveat is that the string needs to have characters contained within it before the function can be used.

int main()
    string str = "Hello"; = 'a';
    cout << str >> endl; // Prints "Hallo"

    return 0;

The above code changes the value at index 1 from 'e' to 'a' and prints out "Hallo"

String Overloaded Operators

Operator Example


The assignment operator may be used in several ways
  • Assigning one string object's value to another string object:
    string string_one = "Hello";
    string string_two;
    string_two = string_one;
  • Assigning a C++ string literal to a string object:
    string string_three;
    string_three = "Goodbye";
  • Assigning a single character ( char ) to a string object:
    string string_four; char ch = 'A';
    string_four = ch;
    string_four = 'Z';


The "plus" operator concatenates
  • two string objects:
    string str1 = "Hello ";
    string str2 = "there";
    string str3 = str1 + str2; // "Hello there"
  • a string object and a character string literal:
    string str1 = "Hello ";
    string str4 = str1 + "there";
  • a string object and a single character:
    string str5 = "The End";
    string str6 = str5 + '!'; // "The End!"


The "+=" operator combines the above assignment and concatenation operations in the way that you would expect, with a string object, a string literal, or a single character as the value on the right-hand side of the operator:
string str1 = "Hello ";
str1 += "there";
The comparison operators return a Boolean (true/false) value indicating whether the specified relationship exists between the two operands. The operands may be:
  • two string objects
  • a string object and a character string literal


The insertion operator writes the value of a string object to an output stream (e.g. cout):
string str1 = "Hello there";
cout << str1 << endl;


The extraction operator reads a character string from an input stream and assigns the value to a string object:

string str1;
cin >> str1;


The subscript operator accesses one character in a string:
string str10 = "abcdefghi";
char ch = str10[3];
cout << ch << endl; // 'd'
str10[5] = 'X';

String Overloaded Operators

Function Description

Initialization (constructor)

A string object may defined without an initializing value, in which case its initial value is an empty string (zero length, no characters):
string str1;
A string object may also be initialized with
  • a string expression:
    string str2 = str1;
    string str3 = str1 + str2;
    string str4 (str2); // Alternate form
  • a character string literal:
    string str4 = "Hello there";
    string str5 ("Goodbye"); // Alternate form
  • a single character. Unfortunately, the expected methods don't work:
    string str6 = 'A'; // Incorrect
    string str7 ('A'); // Also incorrect
    Instead, we must use a special form with two values:
    string str7 (1,'A'); // Correct
    The two values are the desired length of the string and a character to fill the string with. In this case, we are asking for a string of length one, filled with the character A.
  • a substring of another string object:
    string str8 = "ABCDEFGHIJKL";
    Initialize str9 as "CDEFG"
    starting at character 2 ('C') with a length of 5
    (or the rest of the string, if shorter)
    string str9 (str8,2,5);

length, size

size_type length() const;
size_type size() const;

Both of these functions return the length (number of characters) of the string. The size_type return type is an unsigned integer type. (The type name usually must be scoped, as in string::size_type)
string str = "Hello";
string::size_type len;
len = str.length(); // len == 5
len = str.size(); // len == 5


const char* c_str() const;

For compatibility with "older" code, including some C++ library routines, it is sometimes necessary to convert a string object into a character array ("C-style string"). This function does the conversion. For example, you might open a file stream with a user-specified file name:
string filename;

cout << "Enter file name: ";
cin >> filename;

ofstream outfile (filename.c_str());
outfile << "Data" << endl;


string& insert(size_type pos, const string& str);

Inserts a string into the current string, starting at the specified position
string str11 = "abcdefghi";
string str12 = "0123";

str11.insert (3,str12);
cout << str11 << endl; // Prints "abc0123defghi"

str12.insert (1,"XYZ");
cout << str12 << endl; // Prints "0XYZ123"


string& erase(size_type pos, size_type n);

Delete a substring from the current string
string str13 = "abcdefghi";
str12.erase (5,3);
cout << str12 << endl; // Prints "abcdei"


string& replace(size_type pos, size_type n, const string& str);

Delete a substring from the current string, and replace it with another string
string str14 = "abcdefghi";
string str15 = "XYZ";

str14.replace (4,2,str15);

cout << str14 << endl; // Prints "abcdXYZghi"


size_type find (const string& str, size_type pos);

Search for the first occurrence of the substring str in the current string, starting at position pos. If found, returns the position of the first character. If not, returns a special value called string::npos. The member function rfind does the same thing, but returns the position of the last occurrence of the specified string
string str16 = "abcdefghi";
string str17 = "def";

string::size_type pos = str16.find (str17,0);
cout << pos << endl; // 3

pos = str16.find ("AB",0);

if (pos == string::npos)
    cout << "Not found" << endl;


size_type find (const string& str, size_type pos);

Search for the first occurrence of the substring str in the current string, starting at position pos . If found, returns the position of the first character. If not, returns a special value called string::npos. The member function rfind does the same thing, but returns the position of the last occurrence of the specified string.
string str16 = "abcdefghi";
string str17 = "def";
string::size_type pos = str16.find (str17,0);
cout << pos << endl; // 3
pos = str16.find ("AB",0);
if (pos == string::npos)
cout << "Not found" << endl;


string substr (size_type pos, size_type n);

Returns a substring of the current string, starting at position pos and of length n:
string str18 = "abcdefghi";
string str19 = str18.substr (6,2);
cout << str19 << endl; // "gh"

Useful Functions

There are a couple of functions worth mentioning here because you may need them later on in this class. The first function we are going to examine is the the data() function. This function allows you to retrieve the contents of a string. You are probably wondering why you would want to do this but trust me, at some point you may need this function:

int main()
    string str = "Hello";
    string s =;
    cout << s << endl; // Prints "Hello"

The above code simply assigns the data (or string) stored in str into s.

The other function worth mentioning is the assign function. It works in the opposite fashion of data() in that it allows you to set the data of the string:

int main()
    string str;

    str.assign("Hello World");

You may be thinking that there are easier ways to do this. You could for instance simply use the assignment operator to add or get data from the string. You would be correct but what you are going to find in OOP is that there are lots of duplicate functionality like this. This is done to give the user of the class as much flexibility as possible.

Getting Strings from the Keyboard

The cin function works really well when we want to get a single word from the keyboard. The problem with cin is that it stops processing any time it encounters a white space. White spaces are characters that you can't see but are still there. Examples include the spacebar and tab key. This is not good if you want to get a complete line of text from the keyboard.

For instance suppose that you input the following text at the keyboard:

The quick brown fox

cin will stop after the word "The" which may not be very useful for us. To get a complete line of text from the keyboard we need to use the getline function. The getline function has the following definition:

istream& getline (istream& is, string& str, char delim = '\n')

The getline function reads characters from an input stream into a string, stopping when one of the following occurs:

  • An end-of-file condition occurs on the input stream
  • When the maximum number of characters that can fit into a string have been read
  • When a character read from the string is equal to the specified delimiter (newline is the default delimiter); the delimiter character is removed from the input stream, but not appended to the string.

Note: The third parameter (delim) is a default argument. Remember, default arguments are used by default when you don't specify a value for that parameter. 

The return value is a reference to the input stream. If the stream is tested as a logical value (as in an if or while), it is equivalent to true if the read was successful and false otherwise (e.g. end of file).

Terminates on enter key Terminates when a ? is entered

Video - Using the string class

The String Class
The String Class
Using Strings in C++

The stringstream class

The stringstream class provides an interface which allows you to treat strings as if they were input and output streams. This allows you to do things like convert numbers to strings and so on.

To use the stringstream class you must first include <sstream>

Once you have done this you can then use the stream insertion operator to put numbers into the stream:

double d = 3.145;
stringstream ss;
ss << d;

Once you have number assigned to the stringstream class you can then use the str function to convert the the value to a string:

string s = ss.str();

If you need to set precision on how your number will be displayed you can use the precision function. This will allow you to set the total number of digits not just the fraction part. The following simple program will demonstrate setting the precision:

Using the stringstream class
stringstream output
stringstream output
Output of the program on the left

Here the precision was set to 4. This means that 4 total numbers were output. Notice the rounding that takes place before the truncation of the numbers happens.

If you need to clear your instance, you can use the clear function:

stringstream ss;

Converting Number Types

Because all streams are derived from the same classes they all have similar functionality. For instance you can ouput a number converted to hex, octal, or decimal with cout using what I call a flag to the stream:

int x = 32;
cout << hex << x << endl;
cout << oct << x << endl;
cout << dec << x << endl;

The output from above will be:


You can do the same thing with the stringstream class. You can convert a number to hex, octal, or decimal before putting it in a string:

int x = 32;
stringstream ss;

ss << hex << x;
string str = ss.str();

In the above the string named str will hold a value of "20" after the code executes.

Converting Strings To Numbers

It seems appropriate at this time to talk about converting string back to numbers. You might recall from C++ level one that you can use functions like atoi and atof to convert CStrings to numbers:

char str[] = "3.145";
double num = atof(str);

You can still do this with the string class. You simply need to use c_str function that is build into the string class:

string str = "3.145";
double num = atof(str.c_str());

Functions like atoi and atof are older 'C' functions and do not know how to handle CStrings. This is why the c_str function is built into the string class. If you want to use a 'C' function with the string class you will probably have to convert the string to a CString. 

Fortunately the atoi and atof functions have an updated relative. They are:

  • stoi - string to integer
  • stod - string to double
string str = "3.145";
double num = stod(str);

Like atoi and atof these functions will convert up to the point they cannot change a character into a number. Consider the following:

string str = "3.14xyz5";
double num = stod(str);

After these statements execute num will contain 3.14 because stod cannot convert xyz to a valid number. You need to keep this in mind when you are using functions like this. 

Need More?

See what says about the string class

LearnCPP has several tutorials on the string class:


string construction and destruction

string length and capacity

string character access and conversion to CStrings

string appending

string insertion


In the previous section we saw the string class which was included in the Standard Template Library (STL). While the string class is built from a template type it doesn't appear that way to us. We create an instance of the string class the same way we would create an instance of any type of primitive data type.

The vector is our first real look at the Standard Template Library. A vector is considered a container type because it contain a lists of data. Like all STL classes the vector acts like an array that will grow and shrink depending upon the amount of data put into it. What is nice about a vector is that you don't have to worry about all of the memory management that goes along with growing and shrinking an array. The vector class has all of this functionality built into it. A vector then is like an array that will hold any type of data that you want it to and will grow and shrink based on what is being added and removed from it.

Like all of the classes that are part of the STL the vector has a collection of generic algorithms. This includes algorithms to sort, merge, and find elements. We will see the power of the vector as we proceed.

Meet The Vector

In order to use the vector you must first include the vector header in your code:

#include <vector>

The vector is also part of the std namespace and must be stated as such.

The declaration of the vector has the following syntax:

Using this syntax, an instance of a vector can be created to hold any type. You simply place the type you want the instance to hold between the brackets:

vector <int> v;

As stated earlier a vector can hold any type you wish, even a complex type like another class:

vector <string> Strings;

Accessing Elements

Like the string class individual elements of the vector can be accessed using array syntax (brackets):

vector <string> Strings;
string s = Strings[0];

You need to be careful accessing elements this way because initially a vector has no size. If you attempt to access an element that has not had space allocated for it you will get a runtime error:


This error can be fixed by using the resize function to allocate space before attempting to add something to the vector:

vector <string> Strings;

string s = Strings[0];
Strings[1] = "Safe";

You can accomplish the same thing by using an overloaded constructor, which we will cover later, to specify the size of the vector at the time you create the instance:

vector <string> Strings;
string s = Strings[0];

Strings[1] = "Safe";

Specifying the size at the same time you create the instance makes your code one line smaller. If at some point in time you need to add more size to your vector you can use the resize function to accomplish this.

Size v. Capacity

It is important to understand the difference between the size of a vector and its capacity. Simply put:

  • Size - is the number of items that are being held in the vector.
  • Capacity - is the amount of space allocated for the vector

There are four functions that deal with these


  1. reserve(int size) - Changes the capacity to size. It does not allocate space. This needs to be done separately.
  2. int capacity() - Returns a whole number that represents the capacity of the vector


  1. resize(int size) - Allocates memory in the vector to size. This will also affect capacity.
  2. int size() - Returns a whole number that represents the number of elements held in the vector.

You can use the resize function along with the size function to add space to the end of your vector. The following shows how to add size for 10 more elements to the end of the vector:

vector <string> Strings;
Strings.resize(Strings.size() + 10);

Like An Array?

At this point you may be thinking that this is a lot like an array. You still have to know how many items you want to put into the vector, only now you use a function to specify how many items you want it to hold.

To get around this, you can use the push_back function which allocates space in the vector when you attempt to add an item to it. That is, it allocates memory if memory is needed:

vector <int> nums;

for (int i = 0; i < 25; i++)
    nums.push_back(rand() % 100);

In my opinion using the push_back function makes your life much easier. This way you simply let the vector take care of the mundane bookkeeping tasks.


You may recall that it was said that all classes that are part of the STL have some common functionality. Probably the most powerful piece of functionality is that of the iterator.

An iterator is like a type safe pointer that allows you to traverse all of the elements of a container. You can use an iterator to access individual elements, insert items, and remove items. Really the only way to insert and remove items from the middle of the collection is through the use of an iterator. Therefore it is important to learn how to use them.

All STL container classes contain iterators that are used as a means of iterating across the entire collection. The iterator is really like a type safe pointer and as a matter of fact it is used like one. 

To create an iterator you use the scope resolution operator:

vector <int> v;
vector <int>::iterator p;

This assumes that the collection you are iterating through holds data of the type int.

To set the iterator to a starting point we use some of the built-in functions designed for iterators:

p = v.begin();

You can also set it to the end:

p = v.end();

These two functions are useful in for loops to iterate across the collection:

for (p = v.begin(); p < v.end(); p++)

notice that the iterator is used just like a pointer! If you wanted to output what the iterator is pointing at you would treat it like a pointer also:

cout << *p << endl;

Let's look at two programs that basically do the same thing. Fill a vector and print a vector. One uses iterators and the other uses the push_back function and array syntax:

Vector without iterator
Traversing a vector with an iterator.

Useful Vector Functions

 Function Description
at(size_type index)  Returns a reference to the element at the location specified.
back() Returns a reference to the element at the end of the vector.
begin() Returns an iterator to the start of the vector.
clear() Erases the vector.
empty() Returns true if the vector is empty.
end() Returns an iterator one past the end of the vector.
erase(iterator where)
erase(iterator first, iterator last)
Removes a single element or range of elements.
front() Returns a reference to the first element of the vector.
insert(iterator where, const type &val)
insert(iterator where, size_type number, const type &val)
insert(iterator where, iterator input_begin, iterator input_end)
Inserts a value or values into a vector at the specified position(s).
pop_back() Deletes the element at the end of the vector. (Compare with back)
push_back(const type &val) Adds an element to the end of the vector.
size() Returns the number of elements in the vector.
==, != Returns true or false.
<, <=, >, >= Returns true or false
 =  Assigns one vector to another


Video - Using The Vector

Using the Vector
Test Your Knowledge

Can you modify the Fibonacci sequence program in the video to use iterators?

Want More?

See what says about the Vector

Also check out LeanCPP's tutorial on vectors

Enumerated Types

Many times we want to represent a sequential list of items with a corresponding sequential number value. A classic example of this would be days of the week. We could accomplish this the classic way by using a define from the preprocessor:

#define SUNDAY 0
#define MONDAY 1
#define TUESDAY 2
#define WEDNESDAY 3
#define THURSDAY 4
#define FRIDAY 5
#define SATURDAY 6

Or this could also be expressed using a global const:

const int SUNDAY = 0;
const int MONDAY = 1;
const int TUESDAY = 2;
const int WEDNESDAY = 3;
const int THURSDAY = 4;
const int FRIDAY = 5;
const int SATURDAY = 6;

Many of you may not agree with beginning with zero and that is OK. The idea here is that we want to express a sequential list with a numeric value so that we can do something like this:

int dayOfWeek = TUESDAY;

The problem with this is that dayOfWeek is not protected from being assigned any number. Even one that doesn't make sense:

int dayOfWeek = 100;

Enumerated types allow you to create a type that has a range restriction on it. These values are actually constants which means we don't have to concern ourselves with the underlying values. Kind of an abstract concept!!

Enumerated types in C++ are created with the enum keyword:

Using The Enumerated Type

Once you have defined an enumerated type you can assign it to a variable:

You can use an enumerated type to control a loop by assigning it to an int variable:

You can also iterate through an enumerated type using the for loop:

Notice that to move the loop forward day had to be casted to a DaysOfWeek type. This is because the + and ++ operators do not operate on an enumerated type. In the above case you cannot add an int to an enumerated type. The solution then was to cast the int to an enumerated type along with day.

Video - Enumerated Types

Enumerated Types
Enumerated Types
Using Enumerated Types