This is a continuation from the previous Module and a final part of the C++ data encapsulation or abstraction. The source code for this tutorial is available inC++ Data Encapsulation source code. You will find that one of the applications of the data encapsulation are common in C/C++ Integrated Development Environment (IDE) and Visual programming languages.
Able to understand objects and classes through working program examples.
More C++ Working Program Examples and Experiments
Example #1
#include <iostream> using namespace std;
class PlayText { char *NewPointerVariable; public: PlayText(char *InputFromMainProgPointer); int GetData(void); };
PlayText::PlayText(char *InputFromMainProgPointer) { cout<<"Location: constructor implementation part\n"; cout<<"Examine the flow of execution!!!\n"; cout<<"String brought by object from main program is "<<"\""<<InputFromMainProgPointer<<"\""<<"\n"; cout<<"through pointer variable *InputFromMainProgPointer\n"; cout<<"Assign this string to class member pointer variable\n"; cout<<"*NewPointerVariable\n"; cout<<"Next Location: Main program\n\n";
NewPointerVariable = InputFromMainProgPointer; } int PlayText::GetData(void) { cout<<NewPointerVariable<<" = "; return 100; }
void main() { PlayText small("of small size");
cout<<"cout string of main program \"Area of...\" mix \n"; cout<<"with variable NewPointerVariable and silly integer value\n"; cout<<"from implementation part by using small.GetData()....\n"; cout<<"Go to implementation part after next cout, and the output is: \n\n"; cout<<"Area of wall surface "; cout<<small.GetData()<<"\n"; }
|

In this example we can see how efficient regarding the memory allocation and de-allocation have been implemented.
#include <iostream>
using namespace std;
class LearnPointer
{
int *MemVarPoint;
public:
LearnPointer(void);
void SetData(int InputData);
int GetData(void)
{ return *MemVarPoint; };
~LearnPointer(void);
};
LearnPointer::LearnPointer(void)
{
*MemVarPoint = 100;
cout<<"In Constructor: Address of pointer *MemVarPoint is "<<&MemVarPoint<<"\n";
}
void LearnPointer::SetData(int InputData)
{
cout<<"In Method: Address of pointer *MemVarPoint is "<<&MemVarPoint<<"\n";
*MemVarPoint = InputData;
}
LearnPointer::~LearnPointer(void)
{
delete MemVarPoint;
}
void main()
{
LearnPointer SimpleData;
int x;
cout<<"First time: This is constructor value = "<<SimpleData.GetData()<<"\n\n";
SimpleData.SetData(1000);
cout<<"Set the data, call method from implementation part\n";
cout<<"Second time: Override the constructor value = "<<SimpleData.GetData()<<"\n";
cout<<"\nLet get data from user\n";
cout<<"Please key in one integer value: ";
cin>>x;
SimpleData.SetData(x);
cout<<"Third time: New data from user = "<<SimpleData.GetData()<<"\n";
cout<<"\n...See...different data, at different time but"<<endl;
cout<<"same memory (address) allocation..."<<endl;
}

Compile and run the following program example, demonstrating thenew and delete operators.
// testing the new and delete keywords
#include <iostream>
using namespace std;
// a class declaration part
class TestNewDel
{
// member variables...
private:
int TestVar;
char *TestPtr;
// member functions, constructor and destructor...
public:
TestNewDel();
int DisplayValue();
char* DisplayStr();
~TestNewDel();
};
// a class implementation part
// constructor...
TestNewDel::TestNewDel()
{
// test how the constructor is invoked...
static int x=1;
cout<<"In Constructor, pass #"<<x<<endl;
x++;
}
// a simple function returning a value...
int TestNewDel::DisplayValue()
{
return TestVar = 200;
}
// another function returning a string...
char* TestNewDel::DisplayStr()
{
TestPtr = "Testing the new and delete";
return TestPtr;
}
// destructor...
TestNewDel::~TestNewDel()
{
// test how destructor is invoked...
// use static to retain previous value…
static int y=1;
cout<<"In Destructor, pass #"<<y<<endl;
y++;
// explicitly clean up...
TestVar = 0;
}
// main program
int main()
{
// instantiate an object...
// constructor should be invoked...
// with proper memory allocation...
TestNewDel Obj1;
cout<<"In main, testing 1...2...3..."<<endl;
// display the data value...
cout<<"Default constructor value assign to Obj1 = "<<Obj1.DisplayValue()<<endl;
// invoke constructor explicitly...
// remember to clean up later explicitly...
TestNewDel* Obj2 = new TestNewDel;
// reconfirm the allocation for Obj2...
if(!Obj2)
cout<<"Allocation to Obj2 failed!"<<endl;
else
cout<<"Allocation to Obj2 is OK!"<<endl;
// display the data value...
cout<<"Default constructor value "<<"\n assigned to Obj2 = "<<"\'"<<Obj2->DisplayStr()<<"\'"<<endl;
// explicitly clean up the allocation...
delete Obj2;
return 0;
}

The output usingVisual C++ 6.0 (VC60) as shown below look like the cleanup job was done properly. Destructor invoked two times that is forObj1 and Obj2 each.
For Borland users, if you want to see a complete output, please use its debugger.

Next, comment out the following code from the program example:
delete Obj2;
Recompile and re run the program. In this case, let see what happen if we forgot to do the clean up/de-allocation job explicitly for thenew keyword use. The output using VC60 is shown below:
------------------------------------------------------------------------------

Well, the clean up job was not done for Obj2, the destructor only invoked once. So, be careful of this behavior.
// operators overloading example
#include <iostream>
using namespace std;
#include <cassert> // older C header is <assert.h>
// a class declaration part
class TestArray
{
// these overloaded << and >> must be friend of TestArray class...
// so the overloaded << and >> of TestArray class are available
// for the ostream and istream classes, u will learn later...
// ostream and istream are C++ file I/O...
// equal to operator(cout, object) function,
friend ostream &operator<<(ostream &,TestArray &);
// equal to operator(cin, object) function
friend istream &operator>>(istream &,TestArray &);
public:
// default constructor
TestArray(int = 4);
// copy constructor
TestArray(const TestArray &);
// destructor
~TestArray();
// return the size of the an array
int GetSize() const;
// overloaded the assignment operator
const TestArray &operator=(const TestArray &);
// overloaded the == operator
int operator==(const TestArray &) const;
// overloaded the != operator
int operator!=(const TestArray &) const;
// overloaded the [] operator
int &operator[](int);
private:
int *ptr;
int size;
};
// class implementation part
// default constructor for TestArray class
TestArray::TestArray(int ArraySize)
{
size = ArraySize;
ptr = new int[size];
assert(ptr != 0);
for(int i= 0;i<size;i++)
ptr[i] = 0;
}
// copy constructor for TestArray class
TestArray::TestArray(const TestArray &initial)
{
size = initial.size;
ptr = new int[size];
assert(ptr !=0);
for(int i = 0;i<size;i++)
ptr[i] = initial.ptr[i];
}
// destructor for TestArray class
TestArray::~TestArray()
{ delete[ ] ptr; }
// get the array's size
int TestArray::GetSize() const {return size;}
// overloaded the subscript/index operator
int &TestArray::operator[](int index)
{
assert((index >= 0) && (index < size));
return ptr[index];
}
// == comparison, return 1 if true, 0 if false
int TestArray::operator==(const TestArray &rightside) const
{
if (size != rightside.size)
return 0;
for(int i = 0; i< size; i++)
if(ptr[i] != rightside.ptr[i])
return 0;
return 1;
}
// != comparison, return 1 if true, 0 if false
int TestArray::operator!=(const TestArray &rightside) const
{
if (size != rightside.size)
return 1;
for(int i = 0; i<size;i++)
if (ptr[i] != rightside.ptr[i])
return 1;
return 0;
}
// overloaded assignment operator
const TestArray &TestArray::operator=(const TestArray &rightside)
{
if(&rightside != this)
{
delete [ ] ptr;
size = rightside.size;
ptr = new int[size];
assert(ptr !=0);
for(int i = 0; i< size; i++)
ptr[i] = rightside.ptr[i];
}
return *this;
}
// overloaded the >> operator
istream &operator>>(istream &input, TestArray &x)
{
for(int i = 0; i < x.size; i++)
input>>x.ptr[i];
return input;
}
// overloaded the << operator
ostream &operator<<(ostream &output, TestArray &x)
{
int i;
for(i = 0; i < x.size; i++)
{
output<<x.ptr[i]<<' ';
if((i+1)%10==0)
output<<endl;
}
if (i % 10 !=0)
output << endl;
return output;
}
// the main program
int main()
{
// One(3) same as One = 3 and Two will use
// the default constructor value, 4
TestArray One(3), Two;
cout<<"Array One's size is "<<One.GetSize()<<"\nWith initial data: "<<One;
cout<<"Array Two's size is "<<Two.GetSize()<<"\nWith initial data: "<<Two;
cout<<"\nNow, input 7 integers for the arrays:\n";
cin>>One>>Two;
cout<<"\nThen, the arrays content:\n"<<"One[ ]: "<<One<<"Two[ ]: "<<Two;
cout<<"\nNew array, copy of One's array:";
TestArray Three(One);
cout<<"\nThe new array, Three size is "<<Three.GetSize()<<"\nArray initial value: "<<Three;
cout<<"\nTesting: One == Three?\n";
if(One == Three)
cout<<"They are equal\n";
else
cout<<"They are not equal!";
cout<<"\nTesting: One != Two?\n";
if(One != Two)
cout<<"They are not equal\n\n";
cout<<"Assigning Two to One:\n";
One = Two;
cout<<"One: "<<One<<"Two: "<<Two;
cout<<"\nTesting: One == Two?\n";
if(One == Two)
cout<<"They are equal\n";
else
cout<<"They are not equal!\n";
return 0;
}

Well, as an assignment, I pass to you to repackage this program into three files namedtestarray.h as a header file, testarray.cpp as an implementation file and mainarray.cpp as main program.
The following is the simple program example of the complex number for operator and function overloading.
// operator and function overloading
// the classic simple complex number example
#include <iostream>
using namespace std;
class complexnum
{
private:
double p, q;
public:
// constructor forming the a + bi
// overloaded function, with two arguments...
complexnum(double a, double b)
{
p = a;
q = b;
}
// constructor forming the a + 0i
// overloaded function, with one argument...
complexnum(double a)
{
p = a;
q = 0;
}
// returns the real part
double realpart()
{return p; }
// returns the complex part
double imaginarypart()
{ return q; }
// addition operation of two complex numbers
// overloaded operator +
complexnum operator+(complexnum a)
{ return complexnum(a.p + p, a.q + q); }
// addition a complex number and a double
// overloaded operator +
complexnum operator+(double a)
{ return complexnum(p + a, q);}
// subtraction operation of two complex numbers...
// overloaded operator -
complexnum operator-(complexnum a)
{ return complexnum(p - a.p, q - a.q); }
// addition a complex number and a double
// overloaded operator -
complexnum operator-(double a)
{ return complexnum(p - a, q); }
};
// display format for complex number...
// overloaded operator <<
ostream& operator<<(ostream& s, complexnum r)
{
// if no imaginary part...
if(r.imaginarypart() == 0)
// return real part only...
return s<<r.realpart();
// if imaginary part < 0, i.e negative...
else if(r.imaginarypart() < 0 )
{
// and if no real part
if(r.realpart() == 0)
// return imaginary part only...
return s<<r.imaginarypart()<<"i";
else
// return both real and imaginary parts...
return s<<r.realpart()<<r.imaginarypart()<<"i";
}
else
{
// and if no real part
if(r.realpart() == 0)
// return imaginary part only...
return s<<r.imaginarypart()<<"i";
else
// return both, real and imaginary parts...
return s<<r.realpart()<<" + "<<r.imaginarypart()<<"i";
}
}
void main()
{
double a, b;
// get two numbers
cout<<"Enter 2 numbers: ";
cin>>a>>b;
complexnum r = complexnum(a,b);
cout<<"\nThe complex form is r = "<<r<<endl;
complexnum t = complexnum(7.0);
cout<<"\nGiven t = "<<t<<endl;
// addition of complex number and constant…
cout<<"\nThen, r + t = "<<(r+t)<<endl;
// subtraction of complex number and complex number
cout<<"\nThen, r - (4 + 2i) = "<<(r - complexnum(4,2))<<endl;
// addition of complex number and complex number
cout<<"\nThen, r + (2 + 2i) = "<<(r + complexnum(2,2))<<endl;
}
-----------------------------------------------------------------------

Keep in mind that for complex number manipulation you better use thestandard C++ library, <complex>.
// program deftmeth.cpp, default method
#include <iostream>
#include <cstring> // try <string>
using namespace std;
// class declaration part
class def
{
int size; // a simple stored value
char *string; // a name for the stored data
public:
// this overrides the default constructor
def(void);
// this overrides the default copy constructor
def(def &in_object);
// this overrides the default assignment operator
def &operator=(def &in_object);
// this destructor should be required with dynamic allocation
~def(void);
// and finally, a couple of ordinary methods
void set_data(int in_size, char *in_string);
void get_data(char *out_string);
};
// class implementation
def::def(void)
{
size = 0;
string = new char[2];
strcpy(string, "");
}
def::def(def &in_object)
{
size = in_object.size;
string = new char[strlen(in_object.string) + 1];
strcpy(string, in_object.string);
}
def& def::operator=(def &in_object)
{
delete [ ] string;
size = in_object.size;
string = new char[strlen(in_object.string) + 1];
strcpy(string, in_object.string);
return *this; // this pointer
}
def::~def(void)
{
delete [ ] string;
}
void def::set_data(int in_size, char *in_string)
{
size = in_size;
// delete the string size object…
delete [ ] string;
string = new char[strlen(in_string) + 1];
strcpy(string, in_string);
}
void def::get_data(char *out_string)
{
char temp[10];
strcpy(out_string, string);
strcat(out_string, " = ");
itoa(size, temp, 10);
strcat(out_string, temp);
}
// the main program
void main()
{
char buffer[80];
def my_data;
my_data.set_data(8, " small size, override default constructor ");
my_data.get_data(buffer);
cout<<" content of buffer!!\n"<<buffer<<"\n";
def more_data(my_data);
more_data.set_data(12, " medium size, override copy constructor");
my_data.get_data(buffer);
cout<<"\n content of buffer 2nd round!!\n"<<buffer<<"\n";
my_data = more_data;
my_data.get_data(buffer);
cout<<"\n content of buffer 3rd round, assignment overload!!\n"<<buffer<<"\n";
}

Previous program example compiled usingg++.
///// -program objarray.cpp- //////
///// -FEDORA 3, g++ x.x.x- ///////
///// -object and array- //////////
#include <iostream>
using namespace std;
// a class declaration
class wall
{
int length;
int width;
static int extra_data;
// declaration of the extra_data static type
public:
wall(void);
void set(int new_length, int new_width);
int get_area(void);
// an inline function
int get_extra(void) {return extra_data++;}
};
// a class implementation
int wall::extra_data; // an extra_data definition
// a constructor, assigning initial values
wall::wall(void)
{
length = 8;
width = 8;
extra_data = 1;
}
// this method will set a wall size to the two input parameters
void wall::set(int new_length, int new_width)
{
length = new_length;
width = new_width;
}
// this method will calculate and return the area of a wall instance
int wall::get_area(void)
{ return (length * width); }
// the main program
int main()
{
// instantiates 7 objects
wall small, medium, large, group[4];
// assigning values
small.set(5, 7);
large.set(15, 20);
// group[0] uses the default
for(int index=1; index<4; index++)
group[index].set(index + 10, 10);
cout<<"Sending message-->small.get_area()\n";
cout<<"Area of the small wall is "<<small.get_area()<<"\n\n";
cout<<"Sending message-->medium.get_area()\n";
cout<<"Area of the medium wall is "<<medium.get_area()<<"\n\n";
cout<<"Sending message-->large.get_area()\n";
cout<<"Area of the large wall is "<<large.get_area()<<"\n\n";
cout<<"New length/width group[index].set(index + 10, 10)\n";
for(int index=0; index<4; index++)
{
cout<<"Sending message using an array-->group"<<"["<<index<<"].get_area()\n";
cout<<"An array of wall area "<<index<<" is "<<group[index].get_area()<<"\n\n";
}
cout<<"extra_data = 1, extra_data++\n";
cout<<"Sending message using-->small.get_extra() or \n";
cout<<"array, group[0].get_extra()\n";
cout<<"Extra data value is "<<small.get_extra()<<"\n";
cout<<"New Extra data value is "<<medium.get_extra()<<"\n";
cout<<"New Extra data value is "<<large.get_extra()<<"\n";
cout<<"New Extra data value is "<<group[0].get_extra()<<"\n";
cout<<"New Extra data value is "<<group[3].get_extra()<<"\n";
return 0;
}
[bodo@bakawali ~]$ g++ objarray.cpp -o objarray
[bodo@bakawali ~]$ ./objarray
Sending message-->small.get_area()
Area of the small wall is 35
Sending message-->medium.get_area()
Area of the medium wall is 64
Sending message-->large.get_area()
Area of the large wall is 300
New length/width group[index].set(index + 10, 10)
Sending message using an array-->group[0].get_area()
An array of wall area 0 is 64
Sending message using an array-->group[1].get_area()
An array of wall area 1 is 110
Sending message using an array-->group[2].get_area()
An array of wall area 2 is 120
Sending message using an array-->group[3].get_area()
An array of wall area 3 is 130
extra_data = 1, extra_data++
Sending message using-->small.get_extra() or
array, group[0].get_extra()
Extra data value is 1
New Extra data value is 2
New Extra data value is 3
New Extra data value is 4
New Extra data value is 5
tenouk C++ encapsulation program and code examples