Professional Documents
Culture Documents
POLYMORPHISM
OBJECT ORIENTED PROGRAMMING
Advisor: Trương Toàn Thịnh
1
CONTENTS
Introduction
Inheritance
Polymorphism
Access mechanism
Friend function & class
Virtual destroy method
Some techniques
◦ Determine class name
◦ Clone the object
◦ Create the object by using class name
◦ Generalize the scheme & algorithm
2
INTRODUCTION
Inheritance relationship (GENERALIZATION &
SPECIALIZATION) is natural
Example: Rectangle is a special case of
parallelogram, and is a general case of Square
May state:
◦ Square inherits (is) Rectangle
◦ Square is a subclass, Rectangle is a base class
Some benefits:
◦ Subclass reuses the code of base class
◦ Subclass has it owns the properties & methods
◦ Code of base class is also executed when subclass is
executed
3
INHERITANCE
Declaration
#ifndef _Rectangle_h_ #ifndef _Square_h_
#define _Rectangle_h_ #define _Square_h_
#include <iostream> #include “Rectangle.h”
using namespace std;
class Rectangle{ class Square : public Rectangle{
protected: public:
float width, height; Square(float a = 0);
public: void Input(istream&);
Rectangle(float, float); };
float Area(); #endif
void Input(istream&);
};
#endif
6
INHERITANCE
Don’t overuse the inheritance to reuse
some properties.
◦ Example: See DUONGTRON has a center of
DIEM type, so allow DUONGTRON to
inherit DIEM
◦ Example: See RECTANGLE has two
properties width & height, and SQUARE has
ONLY one property, so allow RECTANGLE
to inherit SQUARE and add one more
property.
7
POLYMORPHISM
Make the source code be re-used
Source code becomes general & only is
edited for some special cases
Example
void main(){
Rectangle* pRec;
Rectangle Rec;
Square Sq;
pRec = &Rec;
pRec->Input(cin);
cout<<Rec.Area()<<endl; Input of Rectangle is called No polymorphism
pRec = &Sq;
pRec->Input(cin);
Input of Square is called Polymorphism
cout<<Sq.Area()<<endl;
} 8
POLYMORPHISM
Need to edit the class Rectangle to have
polymorphism (Add virtual into Input)
#ifndef _Rectangle_h_
#define _Rectangle_h_
#include <iostream>
using namespace std;
class Rectangle{
//…
virtual void Input(istream&); Polymorphism method
};
#endif
Square Circle
11
POLYMORPHISM
Example: Note all figure sub classes have
two virtual methods: Input and Area
Ellipse
Input()
Area()
Circle
Input()
Area()
12
POLYMORPHISM
Example: we have two classes Rectangle,
Square and an abstract class Figure.
Adding the class Rectangle
#ifndef _Rectangle_h_
#define _Rectangle_h_
#include “Figure.h”
14
POLYMORPHISM
Example: implement the class Circle.
#ifndef _Circle_h_ #include “Circle.h”
#define _Circle_h_ Circle::Circle(float r){
#include “Ellipse.h” Ra = Rb = r;
class Circle : public Ellipse{ }
public: void Circle::Input(istream& is){
Circle(float r = 0); is>>Ra;
virtual void Input(istream&); Rb = Ra;
}; }
#endif
15
POLYMORPHISM
Example: Implement the class Triangle.
#ifndef _Triangle_h_ #include “Triangle.h”
#define _Triangle_h_ Triangle::Triangle (float a, float h){
#include “Figure.h” baseSide = a; height = h;
class Triangle : public Figure{ }
protected: float Triangle::Area(){
float baseSide, height; return (baseSide * height) / 2;
public: }
Triangle(float a = 0, float h = 0); void Triangle::Input(istream& is){
virtual float Area(); is>>baseSide>>height;
virtual void Input(istream&); }
};
#endif
16
POLYMORPHISM
Example: Need to find the figure with
maximum area in the figure array
#include “Figure.h”
#include “Rectangle.h”
#include “Square.h”
#include “Ellipse.h”
#include “Circle.h”
#include “Triangle.h”
void main(){
Figure* f[] = {new Rectangle(9.3, 9.7), new Circle(4.5),
new Ellipse(4.2, 4.7), new Square(9.5),
new Triangle(10, 6.4), new Ellipse(3.7, 7.8)};
int n = sizeof(f)/sizeof(Figure*);
Figure* fig = findMaxArea(f, n);
if(!fig) cout << fig->Area() << endl;
}; 17
POLYMORPHISM
Example: Implement findMaxArea()
Figure* findMaxArea(Figure* f[], int n){
Figure* a = NULL;
if(n > 0){
a = f[0];
for(int i = 0; i < n; i++){
if(f[i]->Area() > a->Area()){
a = f[i];
}
}
}
return a;
}
18
ACCESS MECHANISM
Each property or method has one of the
three scopes:
◦ public: Accessed from outside and passed to
the sub classes
◦ protected: Only accessed from inside that class
and passed to the sub classes
◦ private: Only accessed from inside that class
and CANNOT pass to the sub classes
19
ACCESS MECHANISM
Example:
class A{ class B : public A{ void main(){
private: public: A obj1(8); B obj2(11);
float a1, a2; int getb(); obj1.a1 = 2;//Wrong
protected: void copyb(A& obj); obj1.c = 7;
float b; int geta2(); }
public: };
float c; int B::getb(){return b;}
A(float); void B::copyb(A& obj){
}; c = obj.c;
A::A(float v){ b = obj.b;//Wrong
a1 = c = v; }
} int B::geta2(){
return a2;//Wrong
}
20
ACCESS MECHANISM
Access table
◦ Public inheritance scope follows base class
◦ Private or protected inheritance scope
follows derived class
sub class Inheritance
base class inheritance private inheritance public
protected
Used in the scope of Used in the scope of Used in the scope of
base class and base class and base class and
Declared protected
become private in become protected in become protected in
sub class sub class sub class
Accessed from Accessed from Accessed from
Declared public outside and become outside and become outside and become
private in sub class protected in sub class public in sub class
Declared private Used in the scope of base class, and cannot be inherited from sub class
21
FRIEND FUNCTION & CLASS
C++ providers the keywork ‘friend’ to
allow the access to private or protected
fields
There are two cases
◦ Friend function: is a friend of the class and
can access to all the fields of that class
◦ Friend class: is a friend of the class and can
access to all the fields of that class
22
FRIEND FUNCTION & CLASS
Example:
class Point{ class RECT{
int x, y; Point P, Q;
public: public:
Point(int x0 = 0, int y0 = 0){ Point Center(){
x = x0; y = y0; Point M;
} M.x = (P.x + Q.x)/2;
friend class RECT; M.y = (P.y + Q.y)/2;
friend void PointMove(Point&, int, int); return M;
}; }};
void PointMove(Point& P, int dx, int dy){ RECT is a friend of Point
P.x+=dx; P.y+=dy;//Right PointMove is a friend of Point
}
void ABC(Point& P, int dx, int dy){
P.x+=dx; P.y+=dy;//Wrong
} 23
VIRTUAL DESTROY METHOD
Destroy method can be declared with polymorphism
Destroy method of child class is firstly called, and
then the one of parent class is called
Rectangle* r = new Square();
r->Input(cin);
//…
delete r;
The statement ‘delete r’ will:
◦ call the destroy method of Rectangle if the Rectangle’s
destroy method has no the keyword ‘virtual’
◦ call the destroy method of Square if the Rectangle’s
destroy method has the keyword ‘virtual’
24
VIRTUAL DESTROY METHOD
The order of constructor & destructor in
int x, y; inheritance
class Point{ class RECT : public Polygon {
char* buffer;
public: public:
Point(int x0 = 0, int y0 = 0){x = x0; y = y0;} RECT(Point A, Point B) :Polygon(4) {
friend class RECT; arr[0] = A; arr[1] = { A.y, B.x };
}; arr[2] = B;arr[3] = { A.x, B.y };
class Polygon { int s = labs((A.x - B.x)*(A.y - B.y));
protected: buffer = new char[s];
int n; Point* arr; }
public: virtual ~RECT() {
Polygon(int size = 0) { if (buffer != NULL) {
n = 0; arr = NULL; delete[]buffer; buffer = NULL;
if (size > 0) { }}};
n = size; arr = new Point[n];
void main() {
}
Polygon* p = new RECT({4,5},{1,1});
}
delete p;
virtual ~Polygon() {
};
if (arr != NULL) {
delete[]arr; arr = NULL; n = 0;}}}; Poly RECT ~RECT ~Poly25
DETERMINE THE CLASS NAME
Example of figures:
◦ We see the Figure pointer can point to the
address of Rectangle, Square…
◦ There are two basic ways of knowing what
type of class of the address
Polymorphism
Inheritance
◦ Polymorphism: add a virtual method returning
the class name
◦ Inheritance: add a property of class name into
the class Figure
26
DETERMINE THE CLASS NAME
Using polymorphism
#ifndef _Figure_h_ #ifndef _Ellipse_h_ #ifndef _Circle_h_
#define _Figure_h_ #define _Ellipse_h_ #define _Cirle_h_
#include <iostream> #define PI 3.14159 #include “Ellipse.h”
using namespace std; #include “Figure.h” class Circle : public Ellipse{
class Figure{ class Ellipse : public Figure{ //…
public: //… public:
//… public: //…
virtual char* className() = 0; //… virtual char* className(){
}; virtual char* className(){ return “Cirle”;
#endif return “Ellipse”; }
} };
}; #endif
#endif
void main(){
Figure* a[] = {new Rectangle(9, 8), new Circle(4.5F), new Ellipse(4.2F, 4.7F)};
int n = sizeof(a)/sizeof(Figure*);
for(int i = 0; i < n; i++)cout << a[i]->className() << endl;
}
27
DETERMINE THE CLASS NAME
Using inheritance
#ifndef _Figure_h_ #include “Ellipse.h”
#define _Figure_h_ Ellipse::Ellipse(float a, float b){
#include <iostream> Ra = a; Rb = b;
using namespace std; name = “Ellipse”;
class Figure{ }
protected: #endif
char* name; #include “Circle.h”
public: Cirle::Cirle(float r){
//… Ra = Rb = r;
char* getClass(){return name;} name = “Cirle”;
}; }
#endif #endif
void main(){
Figure* a[] = {new Rectangle(9, 8), new Circle(4.5F), new Ellipse(4.2F, 4.7F)};
int n = sizeof(a)/sizeof(Figure*);
for(int i = 0; i < n; i++)cout << a[i]->getClass() << endl;
}
28
CLONING THE OBJECT
Circumstance: need to create a copy of
the object a Figure pointer pointing to.
Problem: what type of address the Figure
pointer is pointing to (Rectangle, Square
or Ellipse…)
Solution: build an abstract method called
Clone in class Figure
29
CLONING THE OBJECT
Example:
#ifndef _Figure_h_ #ifndef _Ellipse_h_ #ifndef _Circle_h_
#define _Figure_h_ #define _Ellipse_h_ #define _Cirle_h_
#include <iostream> #define PI 3.14159 #include “Ellipse.h”
using namespace std; #include “Figure.h” class Circle : public Ellipse{
class Figure{ class Ellipse : public Figure{ //…
public: //… public:
//… public: //…
virtual Figure* Clone() = 0; //… virtual Figure* Clone(){
}; virtual Figure* Clone(){ return new Circle(*this);
#endif return new Ellipse(*this); }
} };
}; #endif
#endif
void main(){
Figure* a[] = {new Rectangle(9, 8), new Circle(4.5F), new Ellipse(4.2F, 4.7F)};
int n = sizeof(a)/sizeof(Figure*);
for(int i = 0; i < n; i++)cout << a[i]->Clone()->getClass() << endl;
}
30
CREATE THE OBJECT BY USING
CLASS NAME
Example of Figure: In this case, we need
a function
Figure* createObject(char* clsName),
In which, the parameter clsName is a
string of class name we need to create
Solution:
◦ Building a ‘toolbar’ including all possible
figures
◦ Calling createObject with clsName we need
31
CREATE THE OBJECT BY USING
CLASS NAME
Example
#ifndef _Figure_h_ Array of models
#define _Figure_h_
#include <iostream> Adding a model into the array
#include <vector>
using namespace std;
class Figure{ #include “Figure.h”
private: vector<Figure*> Figure::arr;
static vector<Figure*> arr; void Figure::add(Figure* f){
protected: if(f==NULL) return;
static void add(Figure*); int i = arr.size();
public: while(--i>=0){
static Figure* createObject(char*); Figure* o = arr[i];
virtual char* getClass() = 0; if(strcmp(f->getClass(), o->getClass()) == 0)
virtual Figure* Clone() = 0; break;
}; }
#endif if(i < 0) arr.push_back(f);
}
32
CREATE THE OBJECT BY USING
CLASS NAME
Example Create a copy of the model
#ifndef _Figure_h_
#define _Figure_h_
#include <iostream>
#include “Figure.h”
#include <vector>
Figure* Figure::createObject(char* clsName){
using namespace std;
if(clsName == NULL) return NULL;
class Figure{
int i = arr.size();
private:
while(--i>=0){
static vector<Figure*> arr;
Figure* o = arr[i];
protected:
if(strcmp(clsName, o->getClass()) == 0)
static void add(Figure*);
break;
public:
}
static Figure* createObject(char*);
if(i >= 0) arr[i]->Clone();
virtual char* getClass() = 0;
else return NULL;
virtual Figure* Clone() = 0;
}
};
#endif
33
CREATE THE OBJECT BY USING
CLASS NAME
Example:
#include “Ellipse.h” #include “Circle.h”
Ellipse::Ellipse(float a, float b){ Circle::Circle(float r){
Ra = a; Rb = b; Ra = Rb = r;
add(this); add(this);
} }
void main(){
Figure* a[] = {new Rectangle(9, 8), new Circle(4.5F), new Ellipse(4.2F, 4.7F)};
Figure* rec = Figure::createObject(“Rectangle”);
cout << rec->getClass() << endl;
}
34
CREATE THE OBJECT BY USING
CLASS NAME
Limitation:
◦ The “add” function is always called when any
instance is created
◦ The “add” function loops to find if that
instance is existed.
#include “Figure.h”
vector<Figure*> Figure::arr;
void Figure::add(Figure* f){
if(f==NULL) return;
#include “Ellipse.h”
int i = arr.size();
Ellipse::Ellipse(float a, float b){
while(--i>=0){
Ra = a; Rb = b;
Figure* o = arr[i];
a
add(this);
if(strcmp(f->getClass(), o->getClass()) == 0)
}
break;
}
if(i < 0) arr.push_back(f);
} 35
CREATE THE OBJECT BY USING
CLASS NAME
Solution: using bootrap object technique
◦ Create a static bootrap object in each class
◦ Edit “add” function to remove the loops in it
◦ Don’t call the “add” function in each class
constructor
class Figure{
private: static vector<Figure*> arr; #include “Figure.h”
protected: vector<Figure*> Figure::arr;
static Figure* add(Figure*); Figure* Figure::add(Figure* f){
public: if(f==NULL) return nullptr;
static Figure* createObject(char*); arr.push_back(f);
static const vector<Figure*>& getSampleList() {return arr;} return f;
virtual char* className() = 0; }
virtual Figure* Clone() = 0;
};
36
CREATE THE OBJECT BY USING
CLASS NAME
Continue to fix sub-classes
class Ellipse :public Figure { class Circle :public Ellipse {
static Figure* BootTrapObjectEllipse; static Figure* BootTrapObjectCircle;
protected: double Ra, Rb; public:
public: Circle(float r) :Ellipse(r, r) {}
Ellipse(float a, float b) { Circle(const Circle& o) { Ra = Rb = o.Rb; }
Ra = a; Rb = b; Circle() :Ellipse(0, 0) {}
} const char* className() { return (char*)“Circle”; }
Ellipse(const Ellipse& o) { Figure* Clone() { return new Circle(*this); }
Ra = o.Ra; Rb = o.Rb; };
} Figure* Circle::BootTrapObjectCircle = Figure::add(new Circle());
Ellipse() { Ra = Rb = 0; }
const char* className() { return (char*)“Ellipse”; }
Figure* Clone() { return new Ellipse(*this); }
};
Figure* Ellipse::BootTrapObjectEllipse = Figure::add(new Ellipse());
37
CREATE THE OBJECT BY USING
CLASS NAME
Now is main()
void main(){ Ellipse; ObjID 0123CD30
Its clone object:
char* strTest = (char*)“Circle”; Ellipse; ObjID 01240DF0
for (const auto& fig : Figure::getSampleList()) { Circle; ObjID 0123A6F0
Its clone object:
cout << fig->className() << “; ObjID ” << fig << endl; Circle; ObjID 01241228
Figure* Obj = fig->Clone(); Circle; objID 01241108
cout << “ Its clone object: ” << endl;
cout << “ ” << Obj->className() << “; ObjID ” << Obj << endl;
}
Figure* Obj = Figure::createObject(strTest);
if (Obj == NULL) {
cout << “Cannot create object...” << endl;
}
cout << “ ” << Obj->className() << “; objID ” << Obj << endl;
}
38
CREATE THE OBJECT BY USING
CLASS NAME
We can formulate the style by defining
three macros
#define INIT_MEMBER(CLASS) static Figure* BootTrapObject##CLASS
#define INIT_OBJECT(CLASS) Figure* CLASS::BootTrapObject##CLASS = Figure::addSample(new CLASS())
#define INIT_METHOD(CLASS) virtual Figure* Clone() { return new CLASS(*this); } \
virtual const char* className(){return #CLASS;}
40
GENERALIZE THE SCHEME &
ALGORITHM
In general, to run another program, we need
to perform some steps:
◦ Show the initial message & input
◦ Check the input value
◦ If input value is invalid
Show the error message & require to re-input
◦ Process the request
◦ Print the result
◦ Ask if wanna continue or not
◦ If continuing, start again
◦ Stop the program if wanna stop
41
GENERALIZE THE SCHEME &
ALGORITHM
Implement the class ProgramFrame
#include <iostream> #include “ProgramFrame.h”
using namespace std; void ProgramFrame::startMessage(ostream
class ProgramFrame{ &os){
protected: os<<“Welcome, entering data: ”;
virtual void startMessage(ostream&); }
virtual void Input(istream&) = 0; void ProgramFrame::errorMessage(ostream
virtual void Check() = 0; &os){
virtual void errorMessage(ostream&); os<<“Input data error!”<<endl;
virtual void Output(ostream&) = 0; }
virtual void Process() = 0; bool askContinue(istream& is, ostream& os){
virtual bool continue(istream&, ostream&); os<<“Press y to continue, others to stop: ”;
public: char ch; is>>ch;
void run(istream&, ostream&); return (ch == ‘Y’ || ch == ‘y’);
}; }
#endif
42
GENERALIZE THE SCHEME &
ALGORITHM
Implement the template method ‘run’
void ProgramFrame::run(istream &is, ostream &os){
bool b;
do{
startMessage(os);
Input(is);
if(!Check()){
errorMessage(os);
continue;
}
Process();
Output(os);
b = continue(is, os);
}while(b);
}
43
GENERALIZE THE SCHEME &
ALGORITHM
Example: Testing the class Figure
Figure FigureTest ProgramFrame
44
GENERALIZE THE SCHEME &
ALGORITHM
To test a class, create a testing class.
◦ To test Figure, create FigureTest class
◦ To test Rectangle, create RectangleT class
◦ …
In Figure class, supply virtual methods, such as
isValid() or Input()
In Rectangle class,public
class Rectangle: we Figure{
supply as follows
protected:
float width, height;
public:
// old previous methods
virtual bool isValid() { return width > 0 && height > 0; }
// may override other methods such as Input()
};
45
GENERALIZE THE SCHEME &
ALGORITHM
Build the FigureTest and RectangleT
classes (inheritance & override)
#include “Figure.h” #include “Rectangle.h”
class FigureTest: public ProgramFrame{ class RectangleT: public FigureTest{
Figure* f; public:
public: RectangleT():FigureTest(new Rectangle()){}
FigureTest(Figure* p){f = p;} };
virtual void Input(istream &is){
…
if(!f) f->Input(is);
}
virtual void Check(){
if(!f) return false;
return f->isValid(); void main(){
} RectangleT rectTest;
virtual void Output(ostream &os){ rectTest.run(cin, cout)
if(!f) return; };
os<<f->getClass() << “, Area: ”<<f->Area() << endl;
}
virtual void Process() {}
46
};
ProgramFrame
48
GENERALIZE THE SCHEME &
ALGORITHM
Improved approach
class AlgorithmTest: public ProgramFrame{ class ArrayAlgorithm{
public:
ArrayAlgorithm* mAlg;
virtual void Process(vector<float>& a) = 0;
vector<float> Data; };
public:
AlgorithmTest(ArrayAlgorithm* pAlg){mAlg = pAlg;}
void Input(istream &is){ is >> Data; }
#include <algorithm>
bool Check(){ return Data.size() > 0; } class ArrayReverse: public ArrayAlgorithm{
void Output(ostream &os){ public:
os << “Result after sorting: ”; void Process(vector<float>& a) { reverse(a.begin(), a.end()); }
os << Data; overload
};
} class STL_Sort: public ArrayAlgorithm{
void startMessage(ostream& os){ public:
os << “Enter n, then a[0], …, a[n – 1]: ”; void Process(vector<float>& a) { sort(a.begin(), a.end()); }
} };
void process() { class SelectionS: public ArrayAlgorithm{
if(mAlg != NULL) mAlg->Process(Data); public:
} void Process(vector<float>& a) {/*Implement selection
}; sort*/ }
}; 49
GENERALIZE THE SCHEME &
ALGORITHM
Improved approach (Main function)
void main(){
AlgorithmTest sortTest(new STL_Sort());
sortTest.run(cin, cout);
}
void main(){
AlgorithmTest sortTest(new SelectionS());
sortTest.run(cin, cout);
}
void main(){
AlgorithmTest sortTest(new ArrayReverse());
sortTest.run(cin, cout);
}
50
GENERALIZE THE SCHEME &
ALGORITHM
Improved approach: hart to test with
different datatype, such as int or double
using template
template <class T>
class AlgorithmTest: public ProgramFrame{ class AlgorithmTest: public ProgramFrame{
ArrayAlgorithm* mAlg; ArrayAlgorithm<T>* mAlg;
vector<float> Data; vector<T> Data;
public: public:
AlgorithmTest(ArrayAlgorithm* pAlg){mAlg = pAlg;} AlgorithmTest(ArrayAlgorithm<T>* pAlg){mAlg = pAlg;}
void Input(istream &is){ is >> Data; } void Input(istream &is){ is >> Data; }
bool Check(){ return Data.size() > 0; } bool Check(){ return Data.size() > 0; }
void Output(ostream &os){ void Output(ostream &os){
os << “Result after sorting: ”; os << “Result after sorting: ”;
os << Data; os << Data; template & overload
} }
void startMessage(ostream& os){ void startMessage(ostream& os){
os << “Enter n, then a[0], …, a[n – 1]: ”; os << “Enter n, then a[0], …, a[n – 1]: ”;
} }
void process() { void process() {
if(mAlg != NULL) mAlg->Process(Data); if(mAlg != NULL) mAlg->Process(Data);
} }
}; };
51
GENERALIZE THE SCHEME &
ALGORITHM
Improved approach:
template <class T>
class ArrayAlgorithm{ class ArrayAlgorithm{
public: public:
virtual void Process(vector<float>& a) = 0; virtual void Process(vector<T>& a) = 0;
}; };
#include <algorithm> #include <algorithm>
template <class T>
class ArrayReverse: public ArrayAlgorithm{ class ArrayReverse: public ArrayAlgorithm<T>{
public: public:
void Process(vector<float>& a) { reverse(a.begin(), a.end()); } void Process(vector<T>& a) { reverse(a.begin(), a.end()); }
}; };
template <class T>
class STL_Sort: public ArrayAlgorithm{ class STL_Sort: public ArrayAlgorithm<T>{
public: public:
void Process(vector<float>& a) { sort(a.begin(), a.end()); } void Process(vector<T>& a) { sort(a.begin(), a.end()); }
}; };
template <class T>
class SelectionS: public ArrayAlgorithm{ class SelectionS: public ArrayAlgorithm<T>{
public: public:
void Process(vector<float>& a) {/*Implement selection sort*/ } void Process(vector<T>& a) {/*Implement selection sort*/ }
}; };
52
GENERALIZE THE SCHEME &
ALGORITHM
Improved approach (Main function)
void main(){ void main(){
AlgorithmTest sortTest(new STL_Sort()); AlgorithmTest<double> sortTest(new STL_Sort<double>());
sortTest.run(cin, cout); sortTest.run(cin, cout);
} }
53
COMPARISON WITH C# & JAVA
Inheritance:
◦ Java uses “extend” keyword to inherit
◦ C# and C++ use “:” symbol to inherit
◦ Java and C# ONLY use “public inheritance”
◦ C#’s sub-classes use “new” keyword for all re-
implemented methods existing in base-class
class Figure{ // C# class Figure{ // Java
public float Area() {return 0;} public float Area() {return 0;}
public string className() {return “Figure”;} public String className() {return “Figure”;}
} }
class Rectangle:Figure{ // C# class Rectangle extends Figure{ // Java
private float width, height; private float width, height;
public Rectangle(float w, float h) {width = w; height = h;} public Rectangle(float w, float h) {width = w; height = h;}
public new string className() {return “Rectangle”;} public String className() {return “Rectangle”;}
public new float Area() {return width*height;} public float Area() {return width*height;}
} } 54
COMPARISON WITH C# & JAVA
Polymorphism:
◦ In Java, all methods existing in base-class will
become polymorphic in sub-classes
◦ C# uses “virtual” keyword in base-class and
“override” keyword in sub-class
class Figure{ // C#
public virtual float Area() {return 0;}
public virtual string className() {return “Figure”;}
}
class Rectangle:Figure{ // C#
private float width, height;
public Rectangle(float w, float h) {width = w; height = h;}
public override string className() {return “Rectangle”;}
public override float Area() {return width*height;}
}
class Square:Rectangle{ // C#
public Square(float a) : base(a, a){}
public override string className() {return “Square”;}
} 55
COMPARISON WITH C# & JAVA
Inherit the base-class’s constructors:
◦ Java uses “super” keyword to refer the base-
class, while C# uses “base” keyword
class Square:Rectangle{ // C#
public Square(float a) : base(a, a){}
public override string className() { return “Square”; }
}
class Square extends Rectangle{ // Java
public Square(float a) {super(a, a);}
public override String className() { return “Square”; }
}
56
COMPARISON WITH C# & JAVA
Abstract class and abstract method:
◦ Java and C# use “abstract” keyword to refer a method
impossible to override, similar to “virtual” with zero in C++
◦ C# also uses “virtual” keyword, but refer to an overridable
method
◦ Java need not to use any keyword to refer to an overridable
method, because it is its essence
abstract class Figure{ // C# abstract class Figure{ // Java
public abstract float Area(); public abstract float Area();
public virtual string className() {return “Figure”;} public String className() {return “Figure”;}
} }
#ifndef _Figure_h
#define _Figure_h
class Figure{ // C++
public:
virtual float Area() = 0;
virtual char* className() {return (char*)“Figure”;}
}; #endif 57
COMPARISON WITH C# & JAVA
Root-class (all classes are sub-classes of it)
◦ Java has root class called “Object”
◦ C# has root class called “object”
◦ C++ has no root class
Problems in C++: need to print the information of any classes
Solution:
◦ Create a class called “Object” with virtual method called toString()
◦ All classes must inherit this class and override toString() method
class Object{ // C++ void main(){
public: virtual string toString() = 0; vector<Object*> arr;
}; arr.push_back(new Example());
class TextStream{ TextStream::Write(arr, cout);
static void Write(vector<Object*> objs, ostream& os) { };
for(int i = 0; i < objs.size(); i++) os << objs[i]->toString() << endl;
}
}
class Example: public Object{
public: string toString() {return “This is example class”;}
};
58
COMPARISON WITH C# & JAVA
Root-class (all classes are sub-classes of it)
◦ Java has root class called “Object”
◦ C# has root class called “object”
◦ C++ has no root class
All classes in C# and Java automatically inherit
using System.IO;
“object” and “Object”importclasses
java.io.PrintStream;
public class TextStream{ //C# public class TextStream{ //Java
public static void Write(object[] objs, TextWriter os) { public static void Write(Object[] objs, PrintStream os) {
foreach(object obj in objs) os.WriteLine(“{0}”, obj.ToString()); for(int i = 0; i < objs.length; i++) os.println(objs[i].toString());
} }
} }
using System; import java.util.*;
class MainPrg{ public class MainPrg{
static void Main() { static void main(String[] argv) {
object[] Objs = {new Point2D(3, 5), (object)8, “Test”}; Object[] objs = {new Point2D(3, 5), new Integer(5)};
TextStream.Write(Objs, Console.Out); TextStream.Write(objs, System.out);
} }
} }
59
UPDATES IN C++
(Keyword “override”)
Using “override” at the end of the method’s
signature to emphasize polymorphism
class Object{ // C++
public: virtual string toString() = 0;
};
class Example: public Object{
public: string toString() override {return “This is example class”;}
};
64
UPDATES IN C++
(typeid & decltype)
The typeid() (in <typeinfo> library)
determines the type-identification of a
variable or an instance
Calling typeid(Obj).name() will return the
unique string of name corresponding to
Obj’s type
Calling typeid(Obj).hashcode() will return
the code of Obj’s type
The typeid() is polymorphic
65
UPDATES IN C++ (typeid & decltype)
Old problem: Determine the name of
class Name of class: class Square
pObj class: class Square
string classStrID() { };
return typeid(*this).name(); class Square : public Rectangle {
} INIT_MEMBER(Square);
string className() { public: Square(int D = 0):Rectangle(D, D) {}
string s = classStrID(); int i; };
for (i = 0; i < s.length();++i) { void main() {
if (s[i] < ‘0’ || s[i] > ‘9’) break; RootClass* prc = new Square();
} cout << “Name of class: ” << prc->className() << “\n”;
return s.substr(i); RootClass* pObj = prc->createObject();
} cout << “pObj class:” << pObj->className() << “\n”;
virtual RootClass* createObject() = 0; delete prc; delete pObj;
}; }
66
UPDATES IN C++ (typeid & decltype)
Old problem: Create an instance from a
parameter being a string name of class
Name of class: class Square
#define INIT_MEMBER(CLASS) virtual RootClass* createObject(){return new CLASS;} \
pObj class: class Square
static RootClass* BootObj##CLASS;
#define INIT_OBJECT(CLASS) RootClass* CLASS::BootObj##CLASS =\ class Rectangle : public RootClass {
RootClass::addPrototype(new CLASS()} INIT_MEMBER(Rectangle);
static RootClass* BootObj##CLASS; int Rx, Ry;
class RootClass { public:
protected: virtual int Area() final { return Rx * Ry; }
static map<string, RootClass*> prototypeObjects; Rectangle(int X = 0, int Y = 0):Rx(X), Ry(Y) {}
static RootClass* addPrototype(RootClass* pObj) { };
if (pObj == nullptr) return nullptr; INIT_OBJECT(Rectangle);
prototypeObjects.insert({ pObj->className(), pObj }); class Square : public Rectangle {
return pObj; INIT_MEMBER(Square);
} public: Square(int D = 0):Rectangle(D, D) {}
public: };
static RootClass* createObject(string clsName) { INIT_OBJECT(Square);
if (clsName == “”) return nullptr; void main() {
auto obj = prototypeObjects.find(clsName); RootClass* prc = new Square();
if (obj != prototypeObjects.end()) return obj->second->createObject(); cout << “Name of class: ” << prc->className() << “\n”;
return nullptr; RootClass* pObj = RootClass::createObject(“class Square”);
} cout << “pObj class:” << pObj->className() << “\n”;
// The same as previous… delete prc; delete pObj;
}; } 67
UPDATES IN C++
(typeid & decltype)
The decltype() is not polymorphic
void main() {
Rectangle* pRec = new Square();
decltype(pRec) aFig = new remove_reference<decltype(*pRec)>::type();
cout << aFig->className() << endl;
}
Note:
◦ main() prints “class Rectangle”
◦ decltype(*pRec) decltype((*pRec))
Rectangle&
◦ decltype(pRec) Rectangle*
68