more encapsulation. why bother with encapsulation? encapsulation protects data from accidental...

120
MORE ENCAPSULATION

Upload: howard-greer

Post on 19-Jan-2016

231 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

MORE ENCAPSULATION

Page 2: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

WHY BOTHER WITH ENCAPSULATION?

• Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization.

• Both prevent errors that we are very prone to make since we are thinking only about the internals of the class when we are writing it.

• Later, when we are actually using the class, we have no need to concern ourselves with the internal structure or operation, but can spend our energies using the class to solve the overall problem we are working on.

• The purpose of this chapter is to illustrate how to use some of the traditional aspects of C or C++ with classes and objects.– Pointers to an object as well as pointers within an object. – Arrays embedded within an object, and an array of objects.

Page 3: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• You will recall BOXES1.CPP that it was a very simple program with – the class definition, – the class implementation, and – the main program

all in one file.

• This was selected as a starting point because we will eventually make changes to all parts of the program and it will be convenient to have it all in a single file for illustrative purposes.

• It must be kept in mind however that the proper way to use these constructs is to separate them into the three files as was illustrated in BOX.H, BOX.CPP, and BOXES2.CPP in the last chapter.

• This allows the implementor of box to supply the user with only the interface, namely BOX.H.

• Not giving him the implementation file named BOX.CPP, is practicing the technique of information hiding.

Page 4: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 1 - OBJARRAY.CPP

#include <iostream.h>

class box { int length; int width; static int extra_data; // Declaration of extra_datapublic: box(void); //Constructor void set(int new_length, int new_width); int get_area(void); int get_extra(void) {return extra_data++;}};

Page 5: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 1 - OBJARRAY.CPPint box::extra_data; // Definition of extra_databox::box(void) //Constructor implementation{ length = 8; width = 8; extra_data = 1;}

// This method will set a box size to the two input parametersvoid box::set(int new_length, int new_width){ length = new_length; width = new_width;}

// This method will calculate and return the area of a box instanceint box::get_area(void){ return (length * width);}

Page 6: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 1 - OBJARRAY.CPPint main(){box small, medium, large, group[4]; //Seven boxes to work with

small.set(5, 7); large.set(15, 20); for (int index = 1 ; index < 4 ; index++) //group[0] uses default group[index].set(index + 10, 10);

cout << "The small box area is " << small.get_area() << "\n"; cout << "The medium box area is " << medium.get_area() << "\n"; cout << "The large box area is " << large.get_area() << "\n";

Page 7: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 1 - OBJARRAY.CPPfor (index = 0 ; index < 4 ; index++) cout << "The array box area is " << group[index].get_area() << "\n";

cout << "The extra data value is " << small.get_extra() << "\n"; cout << "The extra data value is " << medium.get_extra() << "\n"; cout << "The extra data value is " << large.get_extra() << "\n"; cout << "The extra data value is " << group[0].get_extra() << "\n"; cout << "The extra data value is " << group[3].get_extra() << "\n";

return 0;}

Page 8: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Example of an array of objects• line

box small, medium, large, group[4]; //Seven boxes to work with

where an array of 4 boxes are defined.

• Recalling the operation of the constructor you will remember that each of the four box objects will be initialized to the values defined within the constructor since the constructor will be executed for each box as they are defined.

• In order to define an array of objects, a constructor for that object with no parameters must be available.

• (We have not yet illustrated a constructor with initializing parameters, but we will in the next program.)

• This is an efficiency consideration since it would probably be an error to initialize all elements of an array of objects to the same value.

Page 9: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Sending a message to one of the objects

• Linefor (int index = 1 ; index < 4 ; index++) //group[0] uses defaultgroup[index].set(index + 10, 10);

defines a for loop that begins with 1 instead of the normal starting index for an array leaving the first object, named group[0], to use

the default values stored when the constructor was called .

• You will observe that sending a message to one of the objects uses the same construct as is used for any object.

• The name of the array followed by its index in square brackets is used to send a message to one of the objects in the array.

• This is illustrated in line

group[index].set(index + 10, 10);

• and the operation of that code should be clear to you.

Page 10: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Sending a message to one of the objects

The other method is called in the output statement in lines

cout << "The array box area is " <<

group[index].get_area() << "\n";

where the area of the four boxes in the group array are listed on the monitor.

Page 11: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• The integer variable named index is defined in line

for (int index = 1 ; index < 4 ; index++) //group[0] uses default

and is still available for use in line for (index = 0 ; index < 4 ; index++) // line 57

since we have not yet left the enclosing block which begins in line 44 and extends to line 68.int main(){box small, medium, large, group[4]; //Seven boxes to work with………..

}• But this is true only if your compiler is aging slightly. If you have a

new compiler, you may find that index is undefined in line 57.

Page 12: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

DECLARATION AND DEFINITION OF A VARIABLE

• An extra variable was included for illustration, the one named extra_data in line

• static int extra_data;

• Since the keyword static is used to modify this variable in line,

static int extra_data; // Declaration of extra_data

it is an external variable and only one copy of this variable will ever exist.

• All seven objects of this class share a single copy of this variable which is global to the objects defined in:

box small, medium, large, group[4]; //Seven boxes to work with

Page 13: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

DEFINITION OF STATIC VARIABLE

• The variable is actually only declared within the class which says it will exist somewhere, but it is not yet defined.

• A declaration says the variable will exist and gives it a name, but the definition actually defines a place to store it somewhere in the computers memory space.

• By definition, a static variable can be declared in a class header but it cannot be defined there, so it is usually defined in the implementation file.

• In this case it is defined in line

• int box::extra_data; // Definition of extra_data

and can then be used throughout the class.

Page 14: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Graphical representation of some of the variables

• Note that the objects named large, group[0], group[1], and group[2] are not shown but they also share the variable named extra_data.

• They are not shown in order to simplify the picture and enhance the clarity.

• Each object has its own personal length and width because they are not declared static.

Page 15: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

How the static variable works

• Line ( with green font)box::box(void) //Constructor implementation{ length = 8; width = 8;

extra_data = 1;}of the constructor sets the single global variable to 1 each time an object is declared.

• Only one assignment is necessary so the other six are actually wasted code.

• It is generally not a good idea to assign a value to a static member in a constructor, but in this case, it illustrates how the static variable works.

• To illustrate that there is only one variable shared by all objects of this class, the method to read its value also increments it.

int get_extra(void) {return extra_data++;}

Page 16: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• Each time it is read in lines,

cout << "The extra data value is " << small.get_extra() << "\n"; cout << "The extra data value is " << medium.get_extra() << "\n";cout << "The extra data value is " << large.get_extra() << "\n";cout << "The extra data value is " << group[0].get_extra() << "\n";cout << "The extra data value is " << group[3].get_extra() << "\n";

• it is incremented and the result of the execution proves that there is only a single variable shared by all objects of this class.

• You will also note that the method named get_extra() is defined within the class declaration so it will be assembled into the final program as inline code.

Page 17: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• 2 static variables we declared in lines

static char out_string[25]; // Format output areastatic char format; // Format to use for output

of DATE.H in chapter 5

• We defined them in lines

char date::format; // This defines the static data memberchar date::out_string[25]; // This defines the static string

of DATE.CPP and overlooked a complete explanation of what they did at that time.

• The declaration and definition of these variables should be considered a good example of the proper place to put these constructs in your classes.

Page 18: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 2 - OBJSTRNG.CPP (1)

#include <iostream.h>

class box { int length; int width; char *line_of_text;public: box(char *input_line); //Constructor void set(int new_length, int new_width); int get_area(void);};

Page 19: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 2 - OBJSTRNG.CPP (1)

box::box(char *input_line) //Constructor implementation{ length = 8; width = 8; line_of_text = input_line;}

// This method will set a box size to the two input parametersvoid box::set(int new_length, int new_width){ length = new_length; width = new_width;}

// This method will calculate and return the area of a box instanceint box::get_area(void){ cout << line_of_text << "= "; return (length * width);}

Page 20: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 2 - OBJSTRNG.CPP (2)

int main(){box small("small box "), //Three boxes to work with medium("medium box "), large("large box ");

small.set(5, 7); large.set(15, 20); cout << "The area of the "; cout << small.get_area() << "\n"; cout << "The area of the "; cout << medium.get_area() << "\n"; cout << "The area of the "; cout << large.get_area() << "\n";

return 0;}

Page 21: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Example of an object with an embedded string.

• Actually, the object does not have an embedded string, it has an embedded pointer, but the two work so closely together that we can study one and understand both.

• You will notice that linechar *line_of_text;

contains a pointer to a char named line_of_text.

• The constructor contains an input parameter which is a pointer to a string which will be copied to the string named line_of_text within the constructor.

• We could have defined the variable line_of_text as an actual array in the class, then used strcpy() to copy the string into the object and everything would have worked the same,

• It should be pointed out that we are not limited to passing a single parameter to a constructor.

• Any number of parameters can be passed, as will be illustrated later.

Page 22: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

A STRING WITHIN AN OBJECT • You will notice that when the three boxes are defined this time, we supply a string

constant as an actual parameter with each declaration which is used by the constructor to assign the string pointer some data to point to.

• When we call get_area() in lines

cout << "The area of the ";cout << small.get_area() << "\n";

cout << "The area of the ";cout << medium.get_area() << "\n";

cout << "The area of the ";cout << large.get_area() << "\n";

we get the message displayed and the area returned.

• It would be prudent to put these operations in separate methods since there is no apparent connection between printing the message and calculating the area, but it was written this way to illustrate that it can be done.

• What this really says is that it is possible to have a method that has a side effect, the message output to the monitor, and a return value, the area of the box.

Page 23: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 3 - OBJINTPT.CPP (1)#include <iostream.h>

class box { int length; int width; int *point;public: box(void); //Constructor void set(int new_length, int new_width, int stored_value); int get_area(void) {return length * width;} // Inline int get_value(void) {return *point;} // Inline ~box(); //Destructor};

Page 24: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 3 - OBJINTPT.CPP (1)

box::box(void) //Constructor implementation{ length = 8; width = 8; point = new int; *point = 112;}// This method will set a box size to the input parametersvoid box::set(int new_length, int new_width, int stored_value){ length = new_length; width = new_width; *point = stored_value;}box::~box(void) //Destructor{ length = 0; width = 0; delete point;}

Page 25: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 3 - OBJINTPT.CPP(2)

int main(){box small, medium, large; //Three boxes to work with

small.set(5, 7, 177); large.set(15, 20, 999); cout << "The small box area is " << small.get_area() << "\n"; cout << "The medium box area is " << medium.get_area() << "\n"; cout << "The large box area is " << large.get_area() << "\n"; cout << "The small box stored value is " << small.get_value() << "\n"; cout << "The medium box stored value is " << medium.get_value() << "\n"; cout << "The large box stored value is " << large.get_value() << "\n";

return 0;}

Page 26: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

AN OBJECT WITH AN INTERNAL POINTER • This program with an embedded pointer which will be used for

dynamic allocation of data. • In line

int *point;

we declare a pointer to an integer variable, but it is only a pointer, there is no storage associated with it.

• The constructor therefore allocates an integer type variable on the heap for use with this pointer in line.point = new int;

Page 27: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

AN OBJECT WITH AN INTERNAL POINTER

• It should be clear that the three objects defined in line

box small, medium, large; //Three boxes to work with

each contain a pointer which points into the heap to three different locations.

• Each object has its own dynamically allocated variable for its own private use.

• Moreover each has a value of 112 stored in its dynamically allocated data because line

*point = 112;stores that value in each of the three locations, once for each call to the constructor.

Page 28: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• In such a small program, there is no chance that we will exhaust the heap, so no test is made for unavailable memory.

• In a real production program, it would be mandatory to test that the value of the returned pointer is not NULL to assure that the data actually did get allocated.

• The method named set() has three parameters associated with it and the third parameter is used to set the value of the new dynamically allocated variable.

• There are two messages passed, one to the small box and one to the large box.

• As before, the medium box is left with its default values.

Page 29: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

destructor is used

• The three areas are displayed followed by the three stored values in the dynamically allocated variables, and we finally have a program that requires a destructor in order to be completely proper.

• If we simply leave the scope of the objects as we do when we leave the main() program, we will leave the three dynamically allocated variables on the heap with nothing pointing to them.

• They will be inaccessible and will therefore represent wasted storage on the heap.

• For that reason, the destructor is used to delete the variable which the pointer named point is referencing, as each object goes out of existence.

Page 30: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

destructor is used

• . In this case, linesbox::~box(void) //Destructor{length = 0;width = 0;delete point;}assign zero to variables that will be automatically deleted.

• Even though these lines of code really do no good, they are legal statements.

• Actually, in this particular case, the variables will be automatically reclaimed when we return to the operating system because all program cleanup is done for us at that time.

• This is an illustration of good programming practice, that of cleaning up after yourself when you no longer need some dynamically allocated variables.

Page 31: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Inline functions

• One other construct should be mentioned again, that of the inline method implementations in line.

int get_area(void) {return length * width;} // Inlineint get_value(void) {return *point;} // Inline

• Inline functions can be used where speed is of the utmost in importance since the code is assembled inline rather than by actually making a method call.

• Since the code is defined as part of the declaration, the system will assemble it inline, and a separate implementation for these methods is not needed.

• If the inline code is too involved, the compiler is allowed to ignore the inline request and will actually assemble it as a separate method, but it will do it invisibly to you and will probably not even tell you about it.

Page 32: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Information hiding or speed up a program

• Remember that we are interested in using information hiding and inline code prevents hiding of the implementation, putting it out in full view.

• Many times you will be more interested in speeding up a program than you are in hiding a trivial implementation.

• Since most inline methods are trivial, you should feel free to use the inline code construct wherever it is expedient.

Page 33: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 4 - OBJDYNAM.CPP (1)

#include <iostream.h>

class box { int length; int width;public: box(void); //Constructor void set(int new_length, int new_width); int get_area(void);};

box::box(void) //Constructor implementation{ length = 8; width = 8;}

Page 34: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 4 - OBJDYNAM.CPP (1)

// This method will set a box size to the two input parametersvoid box::set(int new_length, int new_width){ length = new_length; width = new_width;}

// This method will calculate and return the area of a box instanceint box::get_area(void){ return (length * width);}

Page 35: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

int main(){box small, medium, large; //Three boxes to work withbox *point; //A pointer to a box

small.set(5, 7); large.set(15, 20);

point = new box; // Use the defaults supplied by the constructor

cout << "The small box area is " << small.get_area() << "\n"; cout << "The medium box area is " << medium.get_area() << "\n"; cout << "The large box area is " << large.get_area() << "\n";

cout << "The new box area is " << point->get_area() << "\n"; point->set(12, 12); cout << "The new box area is " << point->get_area() << "\n";

delete point;

return 0;}

Page 36: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

A DYNAMICALLY ALLOCATED OBJECT

• In linebox *point; //A pointer to a box

we define a pointer to an object of type box and since it is only a pointer with nothing to point to, we dynamically allocate an object for it in line,

point = new box; // Use the defaults supplied by the constructor

with the object being created on the heap just like any other dynamically allocated variable.

• When the object is created in line (point = new box; ), the constructor is called automatically to assign values to the two internal storage variables.

• Note that the constructor is not called when the pointer is defined since there is nothing to initialize.

• It is called when the object is allocated.

Page 37: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• Reference to the components of the object are handled in much the same way that structure references are made, through use of the pointer operator as illustrated in lines.

cout << "The new box area is " << point->get_area() << "\n";point->set(12, 12);cout << "The new box area is " << point->get_area() << "\n";

• Of course you can use the pointer dereferencing method without the arrow such as (*point).set(12, 12); as a replacement for line

point->set(12, 12);

but the arrow notation is much more universal and should be used.

Page 38: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

The object is deleted

• Finally, the object is deleted in line

delete point;

and the program terminates. • If there were a destructor for this class, it would be called

automatically as part of the delete statement to clean up the object prior to deletion.

Page 39: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 5 - OBJLIST.CPP (1)

#include <iostream.h>

class box { int length; int width; box *another_box;public: box(void); //Constructor void set(int new_length, int new_width); int get_area(void); void point_at_next(box *where_to_point); box *get_next(void); // return a pointer to an object of the box};

Page 40: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 5 - OBJLIST.CPP (2)box::box(void) //Constructor implementation{ length = 8; width = 8; another_box = NULL;}

// This method will set a box size to the two input parametersvoid box::set(int new_length, int new_width){ length = new_length; width = new_width;}

// This method will calculate and return the area of a box instanceint box::get_area(void){ return (length * width);}

Page 41: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 5 - OBJLIST.CPP (2)

// This method causes the pointer to point to the input parametervoid box::point_at_next(box *where_to_point){ another_box = where_to_point;}

// This method returns the box the current one points tobox *box::get_next(void){ return another_box;}

Page 42: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

int main(){box small, medium, large; //Three boxes to work withbox *box_pointer; //A pointer to a box

small.set(5, 7); large.set(15, 20); cout << "The small box area is " << small.get_area() << "\n"; cout << "The medium box area is " << medium.get_area() << "\n"; cout << "The large box area is " << large.get_area() << "\n";

small.point_at_next(&medium); medium.point_at_next(&large);

box_pointer = &small; box_pointer = box_pointer->get_next(); //&medium cout << "The box pointed to has area " << box_pointer->get_area() << "\n";

return 0;}

Page 43: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

AN OBJECT WITH A POINTER TO ANOTHER OBJECT

• The constructor contains the statement in line

another_box = NULL;

which assigns the pointer the value of NULL to initialize the pointer.

• This is a good idea for all of your programming, don't allow any pointer to point off into space, but initialize all pointers to something.

• By assigning the pointer within the constructor, you guarantee that every object of this class will automatically have its pointer initialized.

• It will be impossible to overlook the assignment of one of these pointers.

Page 44: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

AN OBJECT WITH A POINTER TO ANOTHER OBJECT

• Two additional methods are declared in lines

void point_at_next(box *where_to_point);box *get_next(void);

with the second line having a construct we have not mentioned yet .

• This method returns a pointer to an object of the box class.

• You can return a pointer to a struct in standard C, and this is a parallel construct in C++.

• The implementation in lines

box *box::get_next(void){

return another_box;}

returns the pointer stored as a member variable within the object.

Page 45: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

AN OBJECT WITH A POINTER TO ANOTHER OBJECT

• An extra pointer named box_pointer is defined in the main program for use later and in linesmall.point_at_next(&medium);

• we make the embedded pointer within the small box point to the medium box.

• Linemedium.point_at_next(&large);

makes the embedded pointer within the medium box point to the large box.

• We have effectively generated a linked list with three elements.

void box::point_at_next(box *where_to_point){ another_box = where_to_point;}

Page 46: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

AN OBJECT WITH A POINTER TO ANOTHER OBJECTIn line box_pointer = &small;we make the extra pointer point to the small box. Continuing in line

box_pointer = box_pointer->get_next();

we use it to refer to the small box and update it to the value contained in the small box which is the address of the medium box.

We have therefore traversed from one element of the list to another by sending a message to one of the objects.

If line 71 were repeated exactly as shown, it would cause the extra pointer to refer to the large box, and we would have traversed the entire linked list which is only composed of three elements.

Page 47: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

ANOTHER NEW KEYWORD this

• The word this is defined within any object as being a pointer to the object in which it is contained.

• It is implicitly defined as;

class_name *this;

and is initialized to point to the object for which the member function is invoked.

• This pointer is most useful when working with pointers and especially with a linked list when you need to reference a pointer to the object you are inserting into the list.

• The keyword this is available for this purpose and can be used in any object.

• Actually the proper way to refer to any variable within a list is through use of the predefined pointer this, by writing

this->variable_name,

but the compiler assumes the pointer is used, and we can simplify every reference by omitting the pointer.

Page 48: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 6 - OBJLINK.CPP

#include <iostream.h>

class box { int length; int width; box *another_box;public: box(void); //Constructor void set(int new_length, int new_width); int get_area(void); void point_at_next(box *where_to_point); box *get_next(void);};

Page 49: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 6 - OBJLINK.CPP

box::box(void) //Constructor implementation{ length = 8; width = 8; another_box = NULL;}

// This method will set a box size to the two input parametersvoid box::set(int new_length, int new_width){ length = new_length; width = new_width;}

Page 50: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// This method will calculate and return the area of a box instanceint box::get_area(void){ return (length * width);}

// This method causes the pointer to point to the input parametervoid box::point_at_next(box *where_to_point){ another_box = where_to_point;}

// This method returns the box that this one points tobox *box::get_next(void){ return another_box;}

Page 51: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

int main(){box *start = NULL; // Always points to the start of the listbox *temp; // Working pointerbox *box_pointer; // Used for box creation

// Generate the list for (int index = 0 ; index < 10 ; index++) { box_pointer = new box; box_pointer->set(index + 1, index + 3); if (start == NULL) { start = box_pointer; // First element in list } else { temp->point_at_next(box_pointer); // Additional element } temp = box_pointer; }

Page 52: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Print the list out temp = start; do { cout << "The area is " << temp->get_area() << "\n"; temp = temp->get_next(); } while (temp != NULL);

// Delete the list temp = start; do { temp = temp->get_next(); delete start; start = temp; } while (temp != NULL);

return 0;}

Page 53: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• You will recall that in the last program the only way we had to set or use the embedded pointer was through use of the two methods named point_at_next() and get_next() which are listed in lines

// This method causes the pointer to point to the input parametervoid box::point_at_next(box *where_to_point){ another_box = where_to_point;}

// This method returns the box that this one points tobox *box::get_next(void){ return another_box;}

Page 54: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• We will use these to build up our linked list, then• traverse and print the list.• Finally, we will delete the entire list to free the space on

the heap.

Page 55: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• In lines

box *start = NULL; // Always points to the start of the list

box *temp; // Working pointer

box *box_pointer; // Used for box creation

we define three pointers for use in the program.

• The pointer named start will always point to the beginning of the list, but temp will move down through the list as we create it.

• The pointer named box_pointer will be used for the creation of each object.

Page 56: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

We execute the loop in lines 62 through 75

for (int index = 0 ; index < 10 ; index++){box_pointer = new box;box_pointer->set(index + 1, index + 3);if (start == NULL) {start = box_pointer; // First element in list}else {temp->point_at_next(box_pointer); // Additional element}temp = box_pointer;}to generate the list

Page 57: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• where line

box_pointer = new box;dynamically allocates a new object of the box class, and line

box_pointer->set(index + 1, index + 3);fills it with nonsense data for illustration.

• If this is the first element in the list, the start pointer is set to point to this element, but if elements already exist, the last element in the list is assigned to point to the new element.

• In either case, the temp pointer is assigned to point to the last element of the list, in preparation for adding another element if there is another element to be added.

Page 58: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• In line, temp = start;

the pointer named temp is caused to point to the first element and it is used to increment its way through the list by updating itself in line

temp = temp->get_next();during each pass through the loop.

• When temp has the value of NULL, which it gets from the last element of the list, we are finished traversing the list.

Page 59: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Delete the entire list

• Finally, we delete the entire list by starting at the beginning and deleting one element each time we pass through the loop in lines. do {temp = temp->get_next();delete start;start = temp;} while (temp != NULL);

• A careful study of the program will reveal that it does indeed generate a linked list of ten elements, each element being an object of class box.

• The length of this list is limited by the practicality of how large a list we desire to print out, but it could be lengthened to many thousands of these simple elements provided you have enough memory available to store them all.

Page 60: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 7 - NESTING.CPP

#include <iostream.h>

class mail_info { int shipper; int postage;public: void set(int in_class, int in_postage) {shipper = in_class; postage = in_postage; } int get_postage(void) {return postage;}};

Page 61: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

class box { int length; int width; mail_info label;public: void set(int l, int w, int s, int p) { length = l; width = w; label.set(s, p); } int get_area(void) {return length * width;}};

Page 62: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 7 - NESTING.CPP

int main(){box small, medium, large;

small.set(2, 4, 1, 35); medium.set(5, 6, 2, 72); large.set(8, 10, 4, 98);

cout << "The area is " << small.get_area() << "\n"; cout << "The area is " << medium.get_area() << "\n"; cout << "The area is " << large.get_area() << "\n";

return 0;}

Page 63: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

NESTING OBJECTS • A nested object could be illustrated with your computer in a rather simple

manner.

• The computer itself is composed of many items which work together but work entirely differently, such as a keyboard, a disk drive, and a power supply.

• The computer is composed of these very dissimilar items and it is desirable to discuss the keyboard separately from the disk drive because they are so different.

• A computer class could be composed of several objects that are dissimilar by nesting the dissimilar classes within the computer class.

• If however, we wished to discuss disk drives, we may wish to examine the characteristics of disk drives in general, then examine the details of a hard disk, and the differences of floppy disks.

• This would involve inheritance because much of the data about both drives could be characterized and applied to the generic disk drive then used to aid in the discussion of the other three.

Page 64: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

NESTING OBJECTS

This example program contains a class named box which contains an object of another class embedded within it in line,

mail_info label;

the mail_info class..

This object is available for use only within the class implementation of box because that is where it is defined.

The main() program has objects of class box defined but no objects of class mail_info, so the mail_info class cannot be referred to in the main() program.

int main(){box small, medium, large

Page 65: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

NESTING OBJECTS

• In this case, the mail_info class object is meant to be used internally to the box class and one example is given in lineLabel.set(s, p); }where a message is sent to the label.set() method to initialize the variables.

• Additional methods could be used as needed, but these are given as an illustration of how they can be called.

Page 66: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

NESTING OBJECTS

• Of prime importance is the fact that there are never any objects of the mail_info class declared directly in the main() program, they are inherently declared when the enclosing objects of class box are declared.

• Of course objects of the mail_info class could be declared and used in the main() program if needed, but they are not in this example program.

• In order to be complete, the box class should have one or more methods to use the information stored in the object of the mail_info class.

• If the class and the nested classes require parameter lists for their respective constructors an initialization list can be given.

Page 67: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 8 - OPOVERLD.CPP

#include <iostream.h>

class box { int length; int width;public: void set(int l, int w) {length = l; width = w;} int get_area(void) {return length * width;} friend box operator+(box a, box b); // Add two boxes friend box operator+(int a, box b); // Add a constant to a box friend box operator*(int a, box b); // Multiply box by a constant};

Page 68: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 8 - OPOVERLD.CPP

box operator+(box a, box b) // Add two boxes' widths together{box temp; temp.length = a.length; temp.width = a.width + b.width; return temp;}

box operator+(int a, box b) // Add a constant to a box{box temp; temp.length = b.length; temp.width = a + b.width; return temp;}

Page 69: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 8 - OPOVERLD.CPP

box operator*(int a, box b) // Multiply a box by a constant{box temp; temp.length = a * b.length; temp.width = a * b.width; return temp;}

Page 70: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 8 - OPOVERLD.CPPint main(){box small, medium, large;box temp;

small.set(2, 4); medium.set(5, 6); large.set(8, 10);

cout << "The area is " << small.get_area() << "\n"; cout << "The area is " << medium.get_area() << "\n"; cout << "The area is " << large.get_area() << "\n";

temp = small + medium; cout << "The new area is " << temp.get_area() << "\n"; temp = 10 + small; cout << "The new area is " << temp.get_area() << "\n"; temp = 4 * large; cout << "The new area is " << temp.get_area() << "\n"; return 0;}

Page 71: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

friend function

Declaration and definitionpublic: friend void set(box newp) {newp.length = newp.length+8; newp.width = 8;}

In main function//small.set(2, 4);

set(small);// medium.set(5, 6);set(medium) // large.set(8, 10);set(large);

Page 72: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Characteristics of friend functions

• It is not in the scope of the class to which it has been as friend.

• Since it is not in the scope of the class, it cannot be called using the object of that class.

• Unlike member functions, it cannot access the member names directly and has to use an object name and dot membership operator with each member name.

• It can be declared either in the public or the private part of a class without affecting its meaning.

• Usually, it has the objects as arguments.• The friend functions are often used in operator overloading .

Page 73: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Overloading Binary operators using member function

#include <iostream.h>

class box { int length; int width;public: void set(int l, int w) {length = l; width = w;} int get_area(void) {return length * width;}//friend box operator+(box a, box b) box operator+(box b); // keyword friend removed – member function

friend box operator+(int a, box b); // Add a constant to a box friend box operator*(int a, box b); // Multiply box by a constant};

Page 74: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Overloading Binary operators using member function

box box :: operator+(box b) // Add two boxes' widths together{box temp; temp.length = length; temp.width = width + b.width; return temp;}We should note the following feature of this function:

It receives only one object argument explicitly.It returns a box type valueIt is a member function of box

The function is expected to add two object values and return an object value as the result but receives only one value as argument. Where does the other value come from?

Page 75: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• Now let us look at the statement that invokes this function: temp = small + medium;• We know that a member function can be invoked only by an object

of the same class. • Here, the object small takes responsibility of invoking the function

and medium plays the role of an argument that is passed to the function.

• The above invocation statement is equivalent toTemp = small.operator+(medium)

Therefore, in the operator+() function, the data member of small are accessed directly and the data member of medium (that is passed as an argument) are accessed using the dot operator.

Thus, both the objects are available for the function.

Page 76: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• For example, in the statementtemp.width = width + b.width;

• b.width refers to the object medium and width refers to the object small.

• temp.width is the width of temp that has been created specially to hold the results of addition of small and medium.

• The function returns the object temp to be assigned to temp (in the main function).

• As a rule, in overloading of binary operators, the left-hand operand is used to invoke the operator function and the right-hand operand is passed as an argument.

Page 77: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• How to use overloading with an int type for the first parameter?

temp = 10 + small;

• Without the friend construct we could not use an overloading with an int type variable for the first parameter because we can not send a message to an integer type variable such as int.operator+(object).

Page 78: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

OPERATOR OVERLOADING

• This allows you to define a class of objects and redefine the use of the normal operators.

• The end result is that objects of the new class can be used in as natural a manner as the predefined types.

• In fact, they seem to be a part of the language rather than your own add-on.

• In this case we overload the + operator and the * operator, with the declarations in lines,

friend box operator+(box a, box b); // Add two boxesfriend box operator+(int a, box b); // Add a constant to a boxfriend box operator*(int a, box b); // Multiply box by a constant

Page 79: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

the definitions in lines box operator+(box a, box b) // Add two boxes' widths together{box temp; temp.length = a.length; temp.width = a.width + b.width; return temp;}

box operator+(int a, box b) // Add a constant to a box{box temp; temp.length = b.length; temp.width = a + b.width; return temp;}

box operator*(int a, box b) // Multiply a box by a constant{box temp; temp.length = a * b.length; temp.width = a * b.width; return temp;}

Page 80: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Friend functions• The methods are declared as friend functions so we can use the

double parameter functions as listed.

• If we did not use the friend construct, the function would be a part of one of the objects and that object would be the object to which the message was sent.

• Including the friend construct allows us to separate this method from the object and call the method with infix notation.

• Using this technique, it can be written as object1 + object2 rather than object1.operator+(object2).

• Two of the three operator overloadings use an int for the first parameter so it is necessary to declare them as friend functions.

• There is no upper limit to the number of overloadings for any given operator. Any number of overloadings can be used provided the parameters are different for each particular overloading.

Page 81: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

The header in line

box operator+(box a, box b) // Add two boxes' widths together

illustrates the first overloading where the + operator is overloaded by giving the return type followed by the keyword operator and the operator we wish to overload.

The two formal parameters and their types are then listed in the parentheses

Page 82: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• The normal function operations are given in the implementation of the function in lines.

box temp;temp.length = a.length;temp.width = a.width + b.width;return temp;

• Note that the implementation of the friend functions are not actually a part of the class because the class name is not prepended onto the method name in line.

box operator+(box a, box b) // Add two boxes' widths together

Page 83: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• The biggest difference occurs in line

temp = small + medium;where this method is called by using the infix notation instead of the usual message sending format.

• Since the variables small and medium are objects of the box class, the system will search for a way to use the + operator on two objects of class box and will find it in the overloaded operator+ method we have just discussed.

• The operations within the method implementation can be anything we need them to be, and they are usually much more meaningful than the silly math included here.

Page 84: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

In linetemp = 10 + small;we ask the system to add an int type constant to an object of class box, so the system finds the other overloading of the + operator beginning in linebox operator+(int a, box b) // Add a constant to a box{box temp;temp.length = b.length;temp.width = a + b.width;return temp;}to perform this operation.

Page 85: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• In linetemp = 4 * large;

we ask the system to use the * operator to do something to an int constant and an object of class box, which it satisfies by finding the method in lines.

box operator*(int a, box b) // Multiply a box by a constant{box temp;temp.length = a * b.length;temp.width = a * b.width;return temp;}

Page 86: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• Note that it would be illegal to attempt to use the * operator the other way around, namely large * 4 since we did not define a method to use the two types in that order.

• Another overloading could be given with reversed types, and we could then use the reverse order in a program.

• You will notice that when using operator overloading, we are also using function name overloading since some of the function names are the same.

• When we use operator overloading in this manner, we actually make our programs look like the class is a natural part of the language since it is integrated into the language so well.

• C++ is therefore an extendible language and can be molded to fit the mechanics of the problem at hand.

Page 87: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Unary and Binary operators

• Unary operators, overloaded by means of a member function, take no explicit arguments and return no explicit values, but, those overloaded by means of a friend function, take one reference argument (the object of the relevant class).

• Binary operators overloaded through a member function take one explicit argument and those which are overloaded through a friend function take two explicit arguments.

• When using binary operators overloaded through a member function, the left hand operand must be an object of the relevant class.

• Binary arithmetic operators such as +, -, *, and / must explicitly return a value. They must not attempt to change their own arguments.

Page 88: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

Operators that cannot be overloaded– Sizeof Size of operator– . Membership operator – .* Pointer-to-member operator– :: Scope resolution operator Conditional operator

• Operators where a friend cannot be used– = Assignment operator– () Function call operator– [] Subscripting operator– -> Class member access operator

Page 89: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 9 - FUNCOVER.CPP (1)

#include <iostream.h>

class many_names { int length; int width;public: many_names(void); // Constructors many_names(int len); many_names(int len, int wid); void display(void); // Display functions void display(int one); void display(int one, int two); void display(float number);};

Page 90: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 9 - FUNCOVER.CPP (2)many_names::many_names(void)

{ length = 8; width = 8;

}many_names::many_names(int len)

{ length = len; width = 8;

}many_names::many_names(int len, int wid)

{ length = len;

width = wid;}

void many_names::display(void){

cout << "From void display function, area = " << length * width << "\n";}

Page 91: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 9 - FUNCOVER.CPP (2)

void many_names::display(int one){ cout << "From int display function, area = " << length * width << "\n";}

void many_names::display(int one, int two){ cout << "From two int display function, area = " << length * width << "\

n";}

void many_names::display(float number){ cout << "From float display function, area = " << length * width << "\n";}

Page 92: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 9 - FUNCOVER.CPP (3)

int main(){many_names small, medium(10), large(12, 15);int gross = 144;float pi = 3.1415, payroll = 12.50;

small.display(); small.display(100); small.display(gross,100); small.display(payroll);

medium.display(); large.display(pi);

return 0;}

Page 93: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

FUNCTION OVERLOADING IN A CLASS

• In this program the constructor is overloaded as well as one of the methods to illustrate what can be done.

• This file illustrates some of the uses of overloaded names and a few of the rules for their use.

• You will recall that the function selected is based on the number and types of the formal parameters only.

• The type of the return value is not significant in overload resolution. • In this case there are three constructors.

• The constructor which is actually called is selected by the number and types of the parameters in the definition.

Page 94: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

FUNCTION OVERLOADING IN A CLASS

In line

many_names small, medium(10), large(12, 15);

of the main program the three objects are declared, each with a different number of parameters and inspection of the results will indicate that the correct constructor was called based on the number of parameters

Page 95: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

FUNCTION OVERLOADING IN A CLASS

• In the case of the other overloaded methods, the number and type of parameters is clearly used to select the proper method.

• You will notice that one method uses a single integer and another uses a single float type variable, but the system is able to select the correct one.

• As many overloadings as desired can be used provided that all of the parameter patterns are unique.

• It is the << operator which is part of the cout class, which operates as an overloaded function since the way it outputs data is a function of the type of its input variable or the field we ask it to display.

• Many programming languages have overloaded output functions so you can output any data with the same function name.

Page 96: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 10 - DEFMETHS.CPP

#include <iostream.h>#include <string.h>#include <stdlib.h> class defaults { int size; // A simple stored value

char *string; // A name for the stored data

public:defaults(void); // This overrides the default constructor

defaults(defaults &in_object); // This overrides the default copy constructor defaults &operator=(defaults &in_object); // This overrides the default assignment operator

~defaults(void); // This destructor should be required with dynamic allocation

void set_data(int in_size, char *in_string); // And finally, a couple of ordinary methods

void get_data(char *out_string);};

Page 97: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 10 - DEFMETHS.CPP

defaults::defaults(void){ size = 0; string = new char[2]; strcpy(string, "");}

defaults::defaults(defaults &in_object){ size = in_object.size; string = new char[strlen(in_object.string) + 1]; strcpy(string, in_object.string);}

Page 98: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 10 - DEFMETHS.CPP

defaults &defaults::operator=(defaults &in_object){ delete [] string; size = in_object.size; string = new char[strlen(in_object.string) + 1]; strcpy(string, in_object.string); return *this;}

defaults::~defaults(void){ delete [] string;}

Page 99: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 10 - DEFMETHS.CPP

void defaults::set_data(int in_size, char *in_string){ size = in_size; delete [] string; string = new char[strlen(in_string) + 1]; strcpy(string, in_string);} void defaults::get_data(char *out_string){char temp[10];

strcpy(out_string, string); strcat(out_string, " = "); _itoa(size, temp, 10); strcat(out_string, temp);}

Page 100: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 10 - DEFMETHS.CPP

int main(){char buffer[80];defaults my_data;

my_data.set_data(8, "hat size"); my_data.get_data(buffer); cout << buffer << "\n\n";

defaults more_data(my_data); more_data.set_data(12, "shoe size"); my_data.get_data(buffer); cout << buffer << "\n"; more_data.get_data(buffer); cout << buffer << "\n";

my_data = more_data; my_data.get_data(buffer); cout << buffer << "\n"; more_data.get_data(buffer); cout << buffer << "\n";

return 0;}

Page 101: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

YOU GET SOME METHODS BY DEFAULT • Even if you include no constructors or operator overloadings you get

a few defined automatically by the compiler.

• A few rules that all compiler writers must follow in order to deliver a useful implementation of C++.

1. If no constructors are defined by the writer of a class, the compiler will automatically generate a default constructor and a copy constructor.

2. If the class author includes any constructor in the class, the default constructor will not be supplied by the constructor.

3. If the class author does not include a copy constructor, the compiler will generate one, but if the writer includes a copy constructor, the compiler will not generate one automatically.

4. If the class author includes an assignment operator, the compiler will not include one automatically, otherwise it will generate a default assignment operator.

Page 102: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• Any class declared and used in a C++ program must have some way to construct an object because the compiler, by definition, must call a constructor when we define an object.

• If we don't provide a constructor, the compiler itself will generate one that it can call during construction of the object.

• This is the default constructor and we have used it unknowingly in a lot of our example programs.

• The default constructor does not initialize any of the member variables, but it sets up all of the internal class references it needs, and calls the base constructor or constructors if they exist.

Page 103: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• Line

defaults(void);

declares a default constructor which is called when you define an object with no parameters.

• In this case, the constructor is necessary because we have an embedded string in the class that requires a dynamic allocation and an initialization of the string to the null string.

• It will take little thought to see that our constructor is much better than the default constructor which would leave us with an uninitialized pointer.

• The default constructor is used in line

defaults my_data;

Page 104: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

The copy constructor.• The parameters of a constructor can be of any type except that of

the class to which it belongs. For example,class A{……… ………public: A(A);}

is illegal.

• However, a constructor can accept a reference to its own class as a parameter. Thus, the statementClass A{………………public: A(A&);}

• is valid. In such cases, the constructor is called the copy constructor.

Page 105: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

THE COPY CONSTRUCTOR

• The copy constructor is generated automatically for you by the compiler if you fail to define one yourself.

• It is used to copy the contents of an object to a new object during construction of that new object.

• If the compiler generates it for you, it will simply copy the contents of the original into the new object as a byte by byte copy, which may not be what you want.

• For simple classes with no pointers, that is usually sufficient, but in the present example program, we have a pointer as a class member so a byte by byte copy would copy the pointer from one to the other and they would both be pointing to the same allocated member.

Page 106: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• For this program, we declared our own copy constructor in line

defaults(defaults &in_object);

• and implemented it in lines.

defaults::defaults(defaults &in_object){size = in_object.size;string = new char[strlen(in_object.string) + 1];strcpy(string, in_object.string);}

• A careful study of the implementation will reveal that the new class will indeed be identical to the original, but the new class has its own string to work with.

Page 107: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• Since both constructors contain dynamic allocation, we must assure that the allocated data is destroyed when we are finished with the objects, so a destructor is mandatory as implemented in lines

defaults::~defaults(void){delete [] string;}

• The copy constructor is used in linedefaults more_data(my_data);

Page 108: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

THE ASSIGNMENT OPERATOR • It is not too obvious, but an assignment operator is required for this program

also, because the default assignment operator simply copies the source object to the destination object byte by byte.

• This would result in the same problem we had with copy constructor.

• The assignment operator is declared in linedefaults &operator=(defaults &in_object);

and defined in linesdefaults &defaults::operator=(defaults &in_object){delete [] string;size = in_object.size;string = new char[strlen(in_object.string) + 1];strcpy(string, in_object.string);return *this;}

where we deallocate the old string in the existing object prior to allocating room for the new text and copying the text from the source object into the new object

Page 109: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

• The assignment operator is used in line.

my_data = more_data;

• It should be fairly obvious to the student that when a class is defined which includes any sort of dynamic allocation, the above three methods should be included in addition to the proper destructor.

• If any of the four entities are omitted, the program may have terribly erratic behavior.

Page 110: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

A PRACTICAL EXAMPLE // Chapter 6 - Program 11 - PHRASE.H

#ifndef PHRASE_H#define PHRASE_H

class phrase { char verb[10]; char noun[10]; static char full_phrase[25];public: inline phrase(void); inline void set_noun(char *in_noun); inline void set_verb(char *in_verb); inline char *get_phrase(void); };

#include "phrase.inl"

#endif

• The header file named PHRASE.H includes some inline methods.

• When any implementation uses this class, it must have access to the inline implementation in order to insert the proper inline code for the member functions.

• One way to do this is to put all of the inline methods in a separate file named with the INL extension, then including that file into the end of the .H file as shown here.

• This makes all of the inline code available for the compiler while compiling files that use this class.

Page 111: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 12 - PHRASE.INL

#include <string.h> inline phrase::phrase(void){ strcpy(noun, ""); strcpy(verb, ""); strcpy(full_phrase, "(No text yet)");}

inline void phrase::set_noun(char *in_noun){ strcpy(noun, in_noun);}

inline void phrase::set_verb(char *in_verb){ strcpy(verb, in_verb);}

inline char *phrase::get_phrase(void){ strcpy(full_phrase, verb); strcat(full_phrase, " the "); strcat(full_phrase, noun); return full_phrase;}

The example file named PHRASE.INL contains all of the inline code for this class.

Page 112: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 13 - PHRASE.CPP

#include "phrase.h"

char phrase::full_phrase[25];

• Note that the only reason for this file to exist is to define the static string variable full_phrase.

• Since this is a definition, and therefore some memory is defined, it cannot be placed in the header file.

• If it were placed there, it would seem to work all right in this program because the header file is only used once, but using a bad technique like that would lead to problems later.

• For illustrative purposes, all of the methods were declared inline, so there are no member definitions in this class.

Page 113: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 14 - USEPHRAS.CPP

#include <iostream.h>#include "phrase.h"

int main(){phrase my_text;

cout << "The phrase is ---> " << my_text.get_phrase() << "\n"; my_text.set_noun("baseball"); cout << "The phrase is ---> " << my_text.get_phrase() << "\n"; my_text.set_verb("Throw"); cout << "The phrase is ---> " << my_text.get_phrase() << "\n"; my_text.set_noun("game"); cout << "The phrase is ---> " << my_text.get_phrase() << "\n";

return 0;}

This file uses the phrase class defined in the last two example files.

It is plain to see that this class is no different than any others we have studied.

It simply illustrates a way to package inline code in a simple and very efficient manner.

Page 114: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 15 - TIME.H

// This is probably the minimum usable time class, but is intended as

// an illustration of a class rather than to build an all inclusive

// class for future use. Each student can develop his own to suit

// his own taste.

#ifndef TIME_H#define TIME_H

class time_of_day {protected: int hour; // 0 through 23 int minute; // 0 through 59 int second; // 0 through 59 static char format; // Format to use for

output static char out_string[25]; // Format output

area

• We study a simple time class.

• You should begin by studying the file named TIME.H which will look very similar to the date class header.

• The only major difference in this class from the date class is the overloaded constructors and methods.

• The program is a very practical example that illustrates very graphically that many constructor overloadings are possible.

Page 115: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 15 - TIME.Hpublic: // Constructor - Set time to current time and format to 1 time_of_day(void); time_of_day(int H) {hour = H; minute = 0; second = 0; }; time_of_day(int H, int M) {hour = H; minute = M; second = 0; }; time_of_day(int H, int M, int S) {hour = H; minute = M; second = S; };

// Set the time to these input values // return = 0 ---> data is valid // return = 1 ---> something is out of range int set_time(void); int set_time(int hour_in); int set_time(int hour_in, int minute_in); int set_time(int hour_in, int minute_in, int second_in);

// Select string output format void set_time_format(int format_in) { format = format_in; };

// Return an ASCII-Z string depending on the stored format // format = 1 13:23:12 // format = 2 13:23 // format = 3 1:23 PM char *get_time_string(void);

};#endif

Page 116: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 16 - TIME.CPP

#include <stdio.h> // For the sprintf function#include <time.h> // For the time & localtime functions#include "time.h" // For the class header

char time_of_day::format; // This defines the static data memberchar time_of_day::out_string[25]; // This defines the string

// Constructor - Set time to current time // and format to 1time_of_day::time_of_day(void){time_t time_date;struct tm *current_time;

time_date = time(NULL); current_time = localtime(&time_date); hour = current_time->tm_hour; minute = current_time->tm_min; second = current_time->tm_sec;

format = 1;}

The implementation for the time class is given in this file.It should be pointed out that three of the four overloadings actually call the fourth so that the code did not have to be repeated four times. This is a perfectly good coding practice and illustrates that other member functions can be called from within the implementation.

Page 117: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 16 - TIME.CPP

// Set the time to these input values // return = 0 ---> data is valid // return = 1 ---> something out of rangeint time_of_day::set_time(void) {return set_time(0, 0, 0); };int time_of_day::set_time(int H) {return set_time(H, 0, 0); };int time_of_day::set_time(int H, int M) {return set_time(H, M, 0); };int time_of_day::set_time(int hour_in, int minute_in, int second_in){int error = 0;

if (hour_in < 0) { hour_in = 0; error = 1; } else if (hour_in > 59) { hour_in = 59; error = 1; } hour = hour_in;

if (minute_in < 0) { minute_in = 0; error = 1; } else if (minute_in > 59) { minute_in = 59; error = 1; } minute = minute_in;

if (second_in < 0) { second_in = 0; error = 1; } else if (second_in > 59) { second_in = 59; error = 1; } second = second_in;

return error;}

Page 118: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 16 - TIME.CPP

// Return an ASCII-Z string depending on the stored format // format = 1 13:23:12 // format = 2 13:23 // format = 3 1:23 PMchar *time_of_day::get_time_string(void){ switch (format) { case 2 : sprintf(out_string, "%2d:%02d", hour, minute); break;

case 3 : if (hour == 0) sprintf(out_string, "12:%02d AM", minute); else if (hour < 12) sprintf(out_string, "%2d:%02d AM", hour, minute); else if (hour == 12) sprintf(out_string, "12:%02d PM", minute); else sprintf(out_string, "%2d:%02d PM", hour - 12, minute); break;

case 1 : // Fall through to default so the default is also 1 default : sprintf(out_string, "%2d:%02d:%02d", hour, minute, second); break; }

return out_string;}

This code contains calls that are specific to DOS and are therefore not portable to other platforms. If you are using some other platform, you will need to change the code to make valid calls to your operating system, or simply assign default values to the member variables.

Page 119: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

// Chapter 6 - Program 17 - USETIME.CPP

#include <iostream.h>#include "date.h"#include "time.h"

int main(void){date today;time_of_day now, lunch(12, 15);

cout << "This program executed on " << today.get_date_string() << " at " << now.get_time_string() << "\n";

cout << "We are planning lunch at " << lunch.get_time_string() << " tomorrow.\n";

lunch.set_time(13); cout << "We decided to move lunch to "<< lunch.get_time_string() << " due to a late meeting.\n";

return 0;}

The program uses the time class.

We will use the time class and the date class as the basis for both single and multiple inheritance in the next three chapters.

Page 120: MORE ENCAPSULATION. WHY BOTHER WITH ENCAPSULATION? Encapsulation protects data from accidental corruption, and constructors guarantee proper initialization

WHAT SHOULD BE THE NEXT STEP?

• Because C++ is an extension to ANSI-C, it can be learned in smaller pieces than would be required if you are learning a completely new language.

• You have learned enough to study and completely understand the example program given in chapter 12, the Flyaway adventure game.

• One of your biggest problems is learning to think in terms of object oriented programming.

• It is not a trivial problem if you have been programming in procedural languages for any significant length of time.

• However, it can be learned by experience, so you should begin trying to think in terms of classes and objects immediately.

• Your first project should use only a small number of objects and the remainder of code can be completed in standard procedural programming techniques.

• As you gain experience, you will write more of the code for any given project using classes and objects but every project will eventually be completed in procedural code.

• After you have programmed for a while using the techniques covered up to this point in the tutorial, you can continue on to the next few chapters which will discuss inheritance and virtual functions.