My Training Period: xx hours
This is a continuation from previous Module. Starting from this Module, you have to be careful for the source codes that span more than one line. When you copy and paste to the text or compiler editor, make it in one line! This Module is a transition from C to C++ and Topics of C++ such asFunctions,Arrays,Pointers andStructure that have been discussed in C will not be repeated. The source code is available inC++ Encapsulation source code.
The C++ programming skills and knowledge for this session:
12.5 Objects Data Protection – class Solution
1. // program classobj.cpp - using class instead of struct 2. #include <iostream> 3. using namespace std; 4. 5. // a simple class declaration part 6. class rectangle 7. { 8. // private by default, member variables 9. int height; 10. int width; 11. public: 12. // public, with two methods 13. int area(void); 14. void initialize(int, int); 15. }; 16. 17. // class implementation part 18. int rectangle::area(void) 19. { 20. return (height * width); 21. } 22. 23. void rectangle::initialize(int initial_height, int initial_width) 24. { 25. height = initial_height; 26. width = initial_width; 27. } 28. 29. // a normal structure - compare it with class 30. struct pole 31. { 32. int length; // public 33. int depth; // public 34. }; 35. 36. // main program 37. void main ( ) 38. { 39. rectangle wall, square; 40. pole lamp_pole; 41. 42. // wall.height = 12; 43. // wall.width = 10; 44. // square.height = square.width = 8; 45. // these 3 lines invalid now, private, access only through methods 46. 47. wall.initialize(12,10); // access data through method 48. square.initialize(8,8); 49. lamp_pole.length = 50; // a normal struct data access 50. lamp_pole.depth = 6; 51. cout<<"Using class instead of struct\n"; 52. cout<<"access through method area()\n"; 53. cout<<"------------------------------\n"; 54. cout<<"Area of the wall-->wall.area() = "<<wall.area()<< "\n\n"; 55. cout<<"Area of the square-->square.area()= "<<square.area()<<"\n\n"; 56. // cout<<"---->Non related surface area is 57. // "<<surface_area(square.height,wall.width)<<"\n\n"; 58. // cout<<"---->Wrong area is 59. // "<surface_area(square.height,lamp_pole.depth)<<"\n"; 60. //-----illegal because directly accessing the private data 61. 62. // system("pause"); 63. }
|
In this program, the rectangle is changed to a class with the same two variables which are now private by default, and two public methods which can manipulate the private data. One method is used to initialize the values of the objects instance and the other method returns the area of the object. The two methods are defined in lines 17 through 27 in the manner describe earlier in this module.
The pole is left as a structure to illustrate that the two can be used together and that C++ is truly an extension of ANSI-C.
In line 39, we define two objects, once again named wall and square, but this time we cannot assign values directly to their individual components because they areprivate member variable of the class. The declaration is shown below:
rectangle wall, square;
Figure 12.4 is a graphical illustration of the two objects available for use within the calling program. Lines 42 through 44 are commented out for that reason and the messages are sent to the objects in lines 47 and 48 to tell them to initialize themselves to the values input as parameters.
Thelamp_pole is initialized in the same manner as in the previous program. Using the class in this way prevents us from making the silly calculations we did in the last program, because we can only calculate the area of an object by using the data stored within that object.
The compiler is now being used to prevent the erroneous calculations, so lines 56 through 59 have been commented out.
Even though the square and the wall are both objects of classrectangle, their private data is hidden from each other such that neither can purposefully or accidentally change the other’s data.
This is theabstract data type, a model with a set ofprivate variables for data storage and a set of public operations that can be performed on that stored data.
The only operations that can be performed on the data are those defined by the methods, which prevents many kinds of erroneous operations.
Encapsulation and data hiding bind the data and methods, tightly together and limit the scope and visibility of each.
An object is separated from the rest of the code and carefully developed in complete isolation from it. Only then, it is integrated into the rest of the code with a few of very simple interfaces.
There are two aspects of this technique that really count when you develop software:
First, you can get all of the data you really need through the interface.
Secondly, you cannot get any protected data that you do not need.
You are prevented from getting into the protected area and accidentally corrupting some data stored within it. You also prevented from using the wrong data because the functions available demand a serial or restricted access to the data.
This is a very weak example because it is very easy for a knowledgeable programmer to break the encapsulation, but we will avoid this in next examples.
You can see that object oriented programming is allowing the programmer to partition his programs into smaller portion with their own functionalities, hiding some information, accessing data in controlled manner.
The drawback is this technique will cost you something in efficiency because every access to the elements of the object will require time and inefficiency sending messages.
But, a program made up of objects that closely match the application in real world are much easier to understand and developed than a program that does not. In a real project however, it could be a great savings if one person developed all of the details of the rectangle, programmed it, and made it available to you to simplify the use. That is why a lot of classes have been developed, such as, Microsoft Visual C++ has MFC (Microsoft Foundation Class). We will explore this process in next examples.
Examine program consdest.cpp carefully. It introduces constructors and destructors for initializing and destroying the class member variables respectively. It is very important to do the initialization mainly for pointer variables as you have learned inC/C++ pointers. This program example is identical to the last one, except, a constructor and destructor have been added.
1. // program consdest.cpp - using class instead of struct
2. // with constructor and destructor
3. #include <iostream>
4. using namespace std;
5.
6. // a simple class declaration part
7. class rectangle
8. {
9. // private by default, member variables
10. int height;
11. int width;
12. // public
13. public:
14. rectangle(void); // constructor
15. int area(void);
16. void initialize(int, int);
17. ~rectangle(void); // destructor
18. };
19.
20. // Implementation part
21. rectangle::rectangle(void)
22. //constructor implementation
23. {
24. height = 6;
25. width = 6;
26. }
27.
28. int rectangle::area(void)
29. {
30. return (height * width);
31. }
32.
33. void rectangle::initialize(int initial_height, int initial_width)
34. {
35. height = initial_height;
36. width = initial_width;
37. }
38.
39. // destructor implementation
40. rectangle::~rectangle(void)
41. {
42. height = 0;
43. width = 0;
44. }
45.
46. // a normal structure - compare with class usage
47. struct pole
48. {
49. int length;
50. int depth;
51. };
52.
53. // main program
54. void main ( )
55. {
56. rectangle wall, square;
57. pole lamp_pole;
58.
59.
60. cout<<"Using class instead of struct, using DEFAULT VALUE\n";
61. cout<<"supplied by constructor, access through method area()\n";
62. cout<<"---------------------------------------------------\n\n";
63. cout<<"Area of the wall-->wall.area() = "<<wall.area()<< "\n\n";
64. cout<<"Area of the square-->square.area() = "<<square.area()<<"\n\n";
65. // wall.height = 12;
66. // wall.width = 10;
67. // square.height = square.width = 8;
68. // these 3 lines, invalid now, private access only through methods
69.
70. wall.initialize(12,10); // override the constructor values
71. square.initialize(8,8);
72. lamp_pole.length = 50;
73. lamp_pole.depth = 6;
74.
75. cout<<"Using class instead of struct, USING ASSIGNED VALUE\n";
76. cout<<"access through method area()\n";
77. cout<<"----------------------------------------------------\n";
78. cout<<"Area of the wall-->wall.area() = "<<wall.area()<<"\n\n";
79. cout<<"Area of the square-->square.area()= "<<square.area()<<"\n\n";
80. // cout<<"----> Non related surface area is
81. // "<<surface_area(square.height,wall.width)<<"\n\n";
82. // cout<<"---->Wrong area is
83. // "<surface_area(square.height,lamp_pole.depth)<<"\n";
84.
85. // system("pause");
86. }
-----------------------------------------------------------------------------------------------------------------
The constructor always has the same name as the class itself and is declared in line 14:
rectangle(void) // constructor declaration
...
The constructor is called automatically by the C++ system when the object is declared and prevents the use of an uninitialized variable. The following is the code segment for constructor:
When the object named wall is instantiated in line 56, the constructor is called automatically by the system. The constructor sets the values ofheight and width each to 6 in lines 24 and 25, in the object named wall.
// constructor implementation
rectangle::rectangle(void)
{
height = 6;
width = 6;
}
This is printed out for reference in lines 63 and 64.
cout<<"Area of the wall-->wall.area() = "<<wall.area()<< "\n\n";
cout<<"Area of the square-->square.area() = "<<square.area()<<"\n\n";
Likewise, when the object square is defined in line 56, the values of the height and thewidth of the square are each initialized to 6 when the constructor is called automatically.
A constructor is defined as having the same name as the class itself. In this case both are named rectangle. The constructor cannot have a return type associated with it because of the C++ definition. It actually has a predefined return type, a pointer to the object itself.
Even though both objects are assigned values by the constructor, they are initialized in lines 70 and 71 to the new values as shown below and processing continues.
wall.initialize(12, 10); // override the constructor values
square.initialize(8, 8);
Since we have a constructor that does the initialization, we should probably rename the method named initialize() something else such as reinitialize().
The destructor is very similar to the constructor except that it is called automatically when each of the objects goes out of scope. You will recall that automatic variables have a limited lifetime because they cease to exist when the enclosing block in which they were declared is exited.
When an object is about to be automatically de-allocated, its destructor, if one exists, is called automatically.
A destructor is characterized as having the same name as the class but with a tilde (~) prepend to the class name. A destructor also has no return type.
A destructor is declared in line 17:
~rectangle(void); // destructor declaration
...
And defined in lines 40 through 44.
// destructor implementation
rectangle::~rectangle(void)
{
height = 0;
width = 0;
}
12.7 Object Packaging
|
// a simple class, declaration part
class wall
{
// private by default
int length;
int width;
public:
// constructor declaration
wall(void);
// methods
void set(int new_length, int new_width);
int get_area(void){return (length * width);}
// destructor declaration
~wall(void);
};
The implementation of the class is given in lines 23 through 40 as shown in the following code segment:
// implementation part, a constructor
wall::wall(void)
{
length = 8;
width = 8;
}
// this method will set a wall size to the two inputs
// parameters by default or the initial values
void wall::set(int new_length, int new_width)
{
length = new_length;
width = new_width;
}
// destructor implementation
wall::~wall(void)
{
length = 0;
width = 0;
}
Study this program, compile and run.
1. // program wall1.cpp
2. #include <iostream>
3. using namespace std;
4.
5. // a simple class, declaration part
6. class wall
7. {
8. int length;
9. int width;
10. // private by default
11. public:
12. wall(void);
13. // constructor declaration
14. void set(int new_length, int new_width);
15. // method
16. int get_area(void){return (length * width);}
17. // destructor method
18. ~wall(void);
19. // destructor declaration
20. };
21.
22. // implementation part
23. wall::wall(void)
24. { length = 8;
25. width = 8;
26. }
27. // this method will set a wall size to the two input
28. // parameters by default or initial value,
29.
30. void wall::set(int new_length, int new_width)
31. {
32. length = new_length;
33. width = new_width;
34. }
35.
36. wall::~wall(void)
37. // destructor implementation
38. { length = 0;
39. width = 0;
40. }
41.
42. // main program
43. void main()
44. {
45. wall small, medium, big;
46. // three objects instantiated of type class wall
47.
48. small.set(5, 7);
49. // new length and width for small wall
50. big.set(15, 20);
51. // new length and width for big wall
52. // the medium wall uses the default
53. // values supplied by constructor (8,8)
54.
55. cout<<"Using new value-->small.set(5, 7)\n";
56. cout<<" Area of the small wall is = "<<small.get_area()<<"\n\n";
57. cout<<"Using default/initial value-->medium.set(8, 8)\n";
58. cout<<" Area of the medium wall is = "<<medium.get_area()<<"\n\n";
59. cout<<"Using new value-->big.set(15, 20)\n";
60. cout<<" Area of the big wall is = "<<big.get_area()<<"\n";
61.
62. // system("pause");
63. }
The method in line 16 as shown below contains the implementation for the method as a part of the declaration because it is very simple function.
int get_area(void){return (length * width);}
When the implementation is included in the declaration, it will be assembled inline (inline function) whenever this function is called leading to much faster code execution.
This is because there is no function call overhead when making a call to the method. In some cases this will lead to code that is both smaller and faster.
Inline code implementation in C++ accomplishes the same efficiency that themacro accomplishes in C, and it is better.
Examine thewall.h program carefully. You will see that it is only theclass definition. No details are given of how the various methods are implemented except of course for the inline method namedget_area().
This gives the complete definition of how to use the class with no implementation details. You will notice that it contains lines 6 through 20 of the previous programwall1.cpp. This is called header file and cannot be compiled or run. Create this file and put it together with your main() program folder. You have learnt this step regarding the user defined function inModule 4.
1. // program wall.h, the header file
2.
3. // class declaration part
4. class wall
5. {
6. int length;
7. int width;
8. public:
9. wall(void);
10. // constructor method
11. void set(int new_length, int new_width);
12. // method
13. int get_area(void) {return (length * width);}
14. // another method
15. ~wall(void);
16. // destructor
17. };
18.
19. // this header file cannot be compiled or run
Examine the program wall.cpp carefully. This is the implementation of the methods declared in the class header file (wall.h ). Notice that the class header file is included into this file in line 3 which contains the prototype for the methods and the definitions of the variables to be manipulated.
1. // program wall.cpp, this is implementation file
2.
3. #include "wall.h"
4.
5. wall::wall(void)
6. // constructor implementation
7. {
8. length = 8;
9. width = 8;
10. }
11.
12. // this method implementation will set a
13. // wall size to the two input parameters
14.
15. void wall::set(int new_length, int new_width)
16. {
17. length = new_length;
18. width = new_width;
19. }
20.
21. wall::~wall(void)
22. // destructor implementation
23. {
24. length = 0;
25. width = 0;
26. }
27.
28. // this implementation program should be compiled
29. // without error, generating object file but can't be
30. // run because there is no main() entry point.
The code from lines 23 through 41 of wall1.cpp is contained in this program which is the implementation of the methods declared in the class namedwall.
This file should be compiled but it cannot be run because there is no main entry point which is required for all ANSI-C or C++ programs. Make sure there is no error and the wall.h header file also must be included in your project.
When it is compiled, the object code will be stored in the current directory and available for use by other programs. It should be noted here that the result of the compilation is usually referred to as an object as used in object oriented programming.
The separation of the definition and the implementation is a major step forward in software engineering. The definition file or interface is all the user needs in order to use this class effectively in a program.
User needs no knowledge of the actual implementation of the methods. If he had the implementation available, he may study the code and modify it to make the overall program slightly more efficient, but this would lead to non-portable software and possible bugs’ later if the implementer changed the implementation without changing the interface.
The purpose of object oriented programming is to hide the implementation in such a way that the implementation can not affect anything outside of its own small and well defined boundary or interface. You should compile this implementation program without error and we will use the result with the next program example. The compilation generate object file. No need to run.
Examine thewall2.cpp program and you will find that the class we defined previously is used within this file. In fact, these last three programs, in a single project (and three files!) taken together are identical to the program named wall1.cpp studied earlier.
1. // program wall2.cpp here are the main program,
2. // the actual program that programmer create
3.
4. #include <iostream>
5. using namespace std;
6. #include "wall.h"
7. // a user defined header file containing
8. // class declaration
9.
10. main()
11. {
12. wall small, medium, large;
13. // three objects instantiated of type class wall
14.
15. small.set(5, 7);
16. large.set(15, 20);
17. // the medium wall uses the values
18. // supplied by the constructor
19.
20. cout<<"In this part, we have divided our program into\n";
21. cout<<"three parts.\n"<<"1. Declaration part, wall.h\n";
22. cout<<"2. Implementation part, wall.cpp\n"<<"3. Main program, wall2.cpp\n";
23. cout<<"The output just from the 3rd part i.e. the main \n";
24. cout<<"program is same as the previous program, as follows\n";
25. cout<<"----------------------------------------------------\n\n";
26. cout<<"Area of the small wall surface is = "<<small.get_area()<<"\n";
27. cout<<"Area of the medium wall surface is = "<<medium.get_area()<<"\n";
28. cout<<"area of the big wall surface is = "<<large.get_area()<<"\n";
29. // system("pause");
30. }
The wall.h file is included here, in line 6, since the definition of the wall class is needed to declare three objects and use their methods. There is big difference in wall1.cpp and wall2.cpp as we will see shortly.
We are not merelycalling functions and changing the terminology a little to say we are sending messages. There is an inherent difference in the two operations.
Since the data for each object is tightly bound up within the object, there is no way to get to the data except through the methods and we send a message to the object telling it to perform some operation based on its internally stored data.
However, whenever we call a function, we take along the data for it to work with, as parameters since it doesn’t contain its own data.
Compile and run this program, but when you come to the link step, you will be required to link this program along with the result of the compilation when you compiled the class named wall (wall.cpp). The object file (compiled form) and the header file must be linked together.
To make sure there is no error, follow these steps (Borland C++, Microsoft Visual C++ or other visual IDE):
Create a project.
Create header file wall.h and save it.
Createwall.cpp file, compile it without error, generating object file.
Create themain() program wall2.cpp, compile and run this file.
All three files must be in the same project.
Regarding the use of the "box.h" or <box.h>, please refer tomodule 4.
For Borland C++, the details steps are: First, select the project folder, right click and select Add node.
When the Add to the Project List Dialog box appears, select the desired file(s) and click Open button. Finally compile themain() program.
tenouk fundamental of C++ object oriented tutorial