|
|
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 as Functions, Arrays, Pointers and Structure that have been discussed in C will not be repeated. The source code is available in C++ Encapsulation source code.
C++ abilities:
▪ To understand and use the constructor and destructor.▪ To understand and use the inline function.
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 are private 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.

The lamp_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 class rectangle, their private data is hidden from each other such that neither can purposefully or accidentally change the other’s data.
This is the abstract data type, a model with a set of private 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 in C/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 of height 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 the width 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