|
| My Training Period: xx hours
The source code for this tutorial is available in C++ Polymorphism source code.
17.7 C++ Pointer Rule
17.8 An Actual Virtual Function
1. // program poly6.cpp 2. #include <iostream> 3. using namespace std; 4. 5. // a base class declaration 6. // and the implementation part 7. class vehicle 8. { 9. int wheels; 10. float weight; 11. public: 12. virtual void message(void) 13. // first message() method, with virtual keyword 14. {cout<<"Vehicle message, from vehicle, the base class\n";} 15. }; 16. 17. // a derived class declaration and implementation part 18. class car : public vehicle 19. { 20. int passenger_load; 21. public: 22. void message(void) // second message() 23. {cout<<"Car message, from car, the vehicle derived class\n";} 24. }; 25. 26. class truck : public vehicle 27. { 28. int passenger_load; 29. float payload; 30. public: 31. int passengers(void) {return passenger_load;} 32. }; 33. 34. class boat : public vehicle 35. { 36. int passenger_load; 37. public: 38. int passengers(void) {return passenger_load;} 39. void message(void) // third message() 40. {cout<<"Boat message, from boat, the vehicle derived class\n";} 41. }; 42. 43. // the main program 44. int main() 45. { 46. 47. cout<<"Re add the virtual keyword. Using\n"; 48. cout<<"pointer variables, new and\n"; 49. cout<<"delete keyword\n"; 50. cout<<"-----------------------------------\n"; 51. 52. vehicle *unicycle; 53. 54. unicycle = new vehicle; 55. unicycle->message(); 56. delete unicycle; 57. unicycle = new car; 58. unicycle->message(); 59. delete unicycle; 60. unicycle = new truck; 61. unicycle->message(); 62. delete unicycle; 63. 64. unicycle = new boat; 65. unicycle->message(); 66. delete unicycle; 67. 68. cout<<"\nThe real virtual function huh!\n"; 69. 70. // system("pause"); 71. return 0; 72. }
72 Lines: Output:
|
This poly6.cpp program is identical to the last program example except that the keywordvirtual is added to line 12 to make the method named message() a virtual function. You will notice that the keyword virtual only appears in the base class, all classes that derive this class will have the corresponding method automatically declared virtual by the system.
In this program, we use the single pointer to the base class and allocate, use, thendelete an object of each of the four available classes using the identical code we used in the last program. However, because of the addition of the keyword virtual in line 12, this program acts entirely different from the last program example.
Since the method named message() is declared to be a virtual function in its declaration in the base class, anytime we refer to this function with a pointer to the base class, we actually execute the function associated with one of the derived classes. But this is true only if there is a function available in the derived class and if the pointer is actually pointing to that derived class.
When the program is executed, the output reflects the same output we saw in the other cases when we were actually calling the methods in the derived classes, but now we are using a pointer of the base class type to make the calls.
You will notice that in lines 55, 58, 61, and 65, even though the code is identical in each line, the system is making the decision of which method to actually call based on the type of the pointer when each message is sent. The decision of which method to call is not made during the time when the code is compiled but when the code is executed. This is dynamic binding and can be very useful in some programming situations.
In fact, there are only three different calls made because the class namedtruck does not have a method namedmessage(), so the system simply uses the method from the base class to satisfy the message passed.
For this reason, a virtual function must have an implementation available in the base class which will be used if one is not available in one or more of the derived classes. Note that the message is actually sent to a pointer to the object.
|
// polymorphic functions, virtual keyword program example...
#include <iostream>
using namespace std;
// class declaration and implementation - the base class
class Shape
{
// protected member variables should be available for derived classes...
protected:
char* Color;
public:
// constructor, set the object's data
Shape(){Color = "No Color!";}
~Shape(){};
// virtual base member function...
// return the object's data
virtual char* GetColor(){return Color;}
};
// derived class...
class Rectangle:public Shape
{
// notice the same variable name, it is OK...
char* Color;
public:
Rectangle(){Color = "bLue SkY!";}
~Rectangle(){ }
// derived class member function
// should also be virtual...
char* GetColor(){return Color;}
};
class Square:public Shape
{
char* Color;
public:
Square(){ Color = "yEllOw!";}
~Square(){ }
char* GetColor(){return Color;}
};
class Triangle:public Shape
{
char* Color;
public:
Triangle(){Color = "GrEEn!";}
~Triangle(){ }
char* GetColor(){return Color;}
};
class Circle:public Shape
{
char* Color;
public:
Circle(){Color = "aMbEr!";}
~Circle(){ }
// let set different function name but
// same functionality...
char* GetMyColor(){return Color;}
};
// the main program
int main()
{
// instantiate objects of ... class type
Shape ObjOne;
Rectangle ObjTwo;
Square ObjThree;
Triangle ObjFour;
Circle ObjFive;
cout<<"Non polymorphic, early binding:"<<endl;
cout<<"----------------------------------"<<endl;
cout<<"Shape color: "<<ObjOne.GetColor()<<endl;
cout<<"Rectangle color: "<<ObjTwo.GetColor()<<endl;
cout<<"Square color: "<<ObjThree.GetColor()<<endl;
cout<<"Triangle color: "<<ObjFour.GetColor()<<endl;
// notice the different function name as previous function...
cout<<"Circle color: "<<ObjFive.GetMyColor()<<endl;
cout<<"\nPolymorphic, late binding:"<<endl;
cout<<"--------------------------"<<endl;
// pointer variable of type Shape class...
Shape *VirtualPtr;
// object allocation of type Shape size...
VirtualPtr = new Shape;
cout<<"Shape color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
// de-allocate, clean up...
delete VirtualPtr;
VirtualPtr = new Rectangle;
cout<<"Rectangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
VirtualPtr = new Square;
cout<<"Square color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
// no GetColor() in this derived class, so use the GetColor from the base class...
VirtualPtr = new Circle;
cout<<"Circle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<&VirtualPtr<<"\n\n";
delete VirtualPtr;
// retest..
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
return 0;
}

From the output, notice the memory address (virtual pointer) similarity and one of them has different address.
// program poly6.cpp
#include <iostream>
usingnamespace std;
// a base class declaration, and implementation part
class vehicle
{
int wheels;
float weight;
public:
virtualvoid message(void)
// first message() method, with virtual keyword
{cout<<"Vehicle message, from vehicle, the base class\n";}
};
// derived class declaration and implementation part
class car : public vehicle
{
int passenger_load;
public:
void message(void) // second message()
{cout<<"Car message, from car, the vehicle derived class\n";}
};
class truck : public vehicle
{
int passenger_load;
float payload;
public:
int passengers(void) {return passenger_load;}
};
class boat : public vehicle
{
int passenger_load;
public:
int passengers(void) {return passenger_load;}
void message(void) // third message()
{cout<<"Boat message, from boat, the vehicle derived class\n";}
};
// the main program
int main()
{
cout<<"Re add the virtual keyword. Using\n";
cout<<" pointer variables, new and\n";
cout<<" delete keyword\n";
cout<<"==================================\n";
vehicle *unicycle;
unicycle = new vehicle;
unicycle->message();
delete unicycle;
unicycle = new car;
unicycle->message();
delete unicycle;
unicycle = new truck;
unicycle->message();
delete unicycle;
unicycle = new boat;
unicycle->message();
delete unicycle;
cout<<"\nThe real virtual function huh!\n";
cout<<"==================================\n";
return 0;
}

Previous example compiled usingg++.
///////-polymorph.cpp-/////////
///////-polymorphic functions, virtual function-////////
///////-FEDORA 3, g++ x.x.x-///////
#include <iostream>
using namespace std;
// a class declaration and implementation, a base class
class Shape
{
// protected member variables should be available for derived classes...
protected:
char* Color;
public:
// constructor, set the object's data
Shape(){Color = "No Color!";}
~Shape(){};
// virtual base member function...
// return the object's data
virtual char* GetColor(){return Color;}
};
// derived class...
class Rectangle:public Shape
{
// notice the same variable name, it is OK...
char* Color;
public:
Rectangle(){Color = "bLue SkY!";}
~Rectangle(){}
// derived class member function
// should also be virtual...
char* GetColor(){return Color;}
};
class Square:public Shape
{
char* Color;
public:
Square(){Color = "yEllOw!";}
~Square(){}
char* GetColor(){return Color;}
};
class Triangle:public Shape
{
char* Color;
public:
Triangle(){Color = "GrEEn!";}
~Triangle(){}
char* GetColor(){return Color;}
};
class Circle:public Shape
{
char* Color;
public:
Circle(){Color = "aMbEr!";}
~Circle(){}
// let set different function name but
// same functionality...
char* GetMyColor(){return Color;}
};
// the main program
int main()
{
// instantiate objects of class type...
Shape ObjOne;
Rectangle ObjTwo;
Square ObjThree;
Triangle ObjFour;
Circle ObjFive;
cout<<"Non polymorphic, early binding:"<<endl;
cout<<"----------------------------------"<<endl;
cout<<"Shape color: "<<ObjOne.GetColor()<<". ";
cout<<" The address-->"<<&ObjOne<<endl;
cout<<"Rectangle color: "<<ObjTwo.GetColor()<<". ";
cout<<" The address-->"<<&ObjTwo<<endl;
cout<<"Square color: "<<ObjThree.GetColor()<<". ";
cout<<" The address-->"<<&ObjThree<<endl;
cout<<"Triangle color: "<<ObjFour.GetColor()<<". ";
cout<<" The address-->"<<&ObjFour<<endl;
// notice the different function name as previous function...
cout<<"Circle color: "<<ObjFive.GetMyColor()<<". ";
cout<<"The address-->"<<&ObjFive<<endl;
cout<<"\nPolymorphic, late binding:"<<endl;
cout<<"--------------------------"<<endl;
// pointer variable of type Shape class...
Shape *VirtualPtr;
// object allocation of type Shape size...
VirtualPtr = new Shape;
cout<<"Shape color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
// de-allocate, clean up...
delete VirtualPtr;
VirtualPtr = new Rectangle;
cout<<"Rectangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
VirtualPtr = new Square;
cout<<"Square color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
// no GetColor() in this derived class, so use the GetColor from the base class...
VirtualPtr = new Circle;
cout<<"Circle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<&VirtualPtr<<"\n\n";
delete VirtualPtr;
// retest...
VirtualPtr = new Triangle;
cout<<"Triangle color: "<<VirtualPtr->GetColor()<<endl;
cout<<" VirtualPtr pointer reference = "<<VirtualPtr<<endl;
delete VirtualPtr;
return 0;
}
[bodo@bakawali ~]$ g++ polymorph.cpp -o polymorph
[bodo@bakawali ~]$ ./polymorph
Non polymorphic, early binding:
----------------------------------
Shape color: No Color!. The address-->0xbffffa80
Rectangle color: bLue SkY!. The address-->0xbffffa70
Square color: yEllOw!. The address-->0xbffffa60
Triangle color: GrEEn!. The address-->0xbffffa50
Circle color: aMbEr!. The address-->0xbffffa40
Polymorphic, late binding:
--------------------------
Shape color: No Color!
VirtualPtr pointer reference = 0x804b008
Rectangle color: bLue SkY!
VirtualPtr pointer reference = 0x804b008
Square color: yEllOw!
VirtualPtr pointer reference = 0x804b008
Triangle color: GrEEn!
VirtualPtr pointer reference = 0x804b008
Circle color: No Color!
VirtualPtr pointer reference = 0xbffffa3c
Triangle color: GrEEn!
VirtualPtr pointer reference = 0x804b008
tenouk C++ polymorphism code and program examples
The source code for this tutorial is available inC++ Polymorphism source code.
Check the best selling C/C++, Object Oriented and pattern analysis books at Amazon.com.