You are on page 1of 68

INHERITANCE &

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

◦ Square inherits width & height of Rectangle


◦ Square overrides the method Input
4
INHERITANCE
Definition (implementation)
#include “Rectangle.h” #include “Rectangle.h”
Rectangle::Rectangle(float w, float h) #include “Square.h”
{ void main(){
width = w; height = h; Rectangle Rec;
} Square Sq;
void Rectangle::Input(istream& is){ Rec.Input(cin);
float is>>width>>height; cout<<Rec.Area()<<endl;
} Sq.Input(cin);
float Rectangle::Area(){ cout<<Sq.Area()<<endl;
return width*height; }
}
#include “Square.h”
Square::Square(float a ){
width = height = a;
}
void Square::Input(istream& is){
is>>width; height = width;
} 5
INHERITANCE
The pointer of base class can point to the
address of subclass (derived class)
Example:
Rectangle* pRec;
Square Sq(10);
pRec = &Sq;
pRec = new Square(5);
C++ can switch off this feature.

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

Method ‘Input’ in Square becomes


polymorphism (Needn’t add ‘virtual’ in
Square)
9
POLYMORPHISM
Some classes are nonsense when creating
the instance  Abstract class
Abstract class contains at least one
abstract method
Abstract method is the one is declared
and has no implementation
#ifndef _Figure_h_
#define _Figure_h_
#include <iostream>
using namespace std;
class Figure{
public:
virtual void Input(istream&) = 0;
virtual float Area() = 0; Abstract method
};
#endif 10
POLYMORPHISM
Example: build the system of figures
following the inheritance tree
Figure

Rectangle Ellipse Triangle

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”

class Rectangle : Figure{


protected:
float width, height;
public:
Rectangle(float, float);
virtual float Area();
virtual void Input(istream&);
};
#endif 13
POLYMORPHISM
Example: implement the class Ellipse.
#ifndef _Ellipse_h_ #include “Ellipse.h”
#define _Ellipse_h_ Ellipse::Ellipse(float a, float b){
#define PI 3.14159F Ra = a; Rb = b;
#include “Figure.h” }
class Ellipse : public Figure{ float Ellipse::Area(){
protected: return PI * Ra * Rb;
float Ra, Rb; }
public: void Ellipse::Input(istream& is){
Ellipse(float a = 0, float b = 0); is>>Ra>>Rb;
virtual float Area(); }
virtual void Input(istream&);
};
#endif

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);
} }

#include “Rectangle.h” #include “Square.h”


Rectangle::Rectangle(float w, Square::Square(float a){
float h){ width = height = a;
width = w; height = h; 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;}

We put them in the appropriate position


class Ellipse :public Figure { class Ellipse :public Figure {
static Figure* BootTrapObjectEllipse; INIT_MEMBER(Ellipse);
protected: double Ra, Rb; protected: double Ra, Rb;
public: public:
Ellipse(float a, float b) { Ra = a; Rb = b; } Ellipse(float a, float b) { Ra = a; Rb = b; }
Ellipse(const Ellipse& o) { Ra = o.Ra; Rb = o.Rb; } Ellipse(const Ellipse& o) { Ra = o.Ra; Rb = o.Rb; }
Ellipse() { Ra = Rb = 0; } Ellipse() { Ra = Rb = 0; }
const char* className() { return (char*)“Ellipse”; }
Figure* Clone() { return new Ellipse(*this); } INIT_METHOD(Ellipse);
}; };
Figure* Ellipse::BootTrapObjectEllipse = Figure::add(new Ellipse()); INIT_OBJECT(Ellipse);
39
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;}

We put them in the appropriate position


class Circle :public Ellipse { class Circle :public Ellipse {
static Figure* BootTrapObjectCircle; INIT_MEMBER(Circle);
public: public:
Circle(float r) :Ellipse(r, r) {} Circle(float r) :Ellipse(r, r) {}
Circle(const Circle& o) { Ra = Rb = o.Rb; } Circle(const Circle& o) { Ra = Rb = o.Rb; }
Circle() :Ellipse(0, 0) {} Circle() :Ellipse(0, 0) {}
const char* className() { return (char*)“Circle”; }
Figure* Clone() { return new Circle(*this); } INIT_METHOD(Circle);
}; };
Figure* Circle::BootTrapObjectCircle = Figure::add(new Circle()); INIT_OBJECT(Circle);

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

Rectangle Ellipse Triangle RectangleT EllipseT TriangleT

Square Circle SquareT CircleT

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

GENERALIZE THE SCHEME &


ALGORITHM
Example: Testing the sort algorithm
(naïve approach)
SortAlgTry

class SortAlgTry: public ProgramFrame{ void main(){


vector<float> a; int n; SortAlgTry sortTry;
public: sortTry.run(cin, cout);
SortAlgTry(){} };
void Input(istream &is){
is >> n;
if(n <= 0) return;
a.resize(n);
for(int i = 0; i < a.size(); i++) is >> a[i];
}
bool Check(){ return n > 0; }
void Output(ostream &os){
for(int i = 0; i < a.size(); i++) os << a[i] << “ ”;
os << endl;
}
void process() {// another algorithm}
}; 47
GENERALIZE THE SCHEME &
ALGORITHM
Naïve approach: hart to test other kinds of
algorithms => Need improve
ArrayAlgorithm AlgorithmTest ProgramFrame

STL_Sort ArrayReverse SelectionS

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);
} }

void main(){ void main(){


AlgorithmTest sortTest(new SelectionS()); AlgorithmTest<short> sortTest(new SelectionS<short>());
sortTest.run(cin, cout); sortTest.run(cin, cout);
} }

void main(){ void main(){


AlgorithmTest sortTest(new ArrayReverse()); AlgorithmTest<int> sortTest(new ArrayReverse<int>());
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”;}
};

This keyword helps notifying errors when:


◦ No method with keyword “virtual” is in base-class
◦ May be incompatible with the signature method in
base-class
60
UPDATES IN C++
(Keyword “final”)
Using “final” to declare final class or
final method which are not inheritable or
overridden
class Figure{ // C++ Figure ERROR
public: virtual float Area() = 0; Rectangle
}; Area() Square {leaf}
class Rectangle: public Figure{
float Dx, Dy; <<final>>Area() JolieSquare
public: virtual float Area() final;
};
class Square final: public Rectangle{
public: float Area() override; // Error because Area() is a final method in Rectangle
};
class JolieSquare : public Square{// Error because Square is a final class
// Some instruction
}; 61
UPDATES IN C++
(Keywords “explicit” and “delete”)
C++’s original implementation allows
implicitly casting when assigning the
values compatible with the inputs of
another constructor, similar to comparison
operators class PhanSo {
int tu, mau;
public:
PhanSo();
PhanSo(int);
PhanSo(int, int);
};
PhanSo::PhanSo() { tu = 0; mau = 1; }
PhanSo::PhanSo(int t) { tu = t; mau = 1; }
PhanSo::PhanSo(int t, int m) { tu = t; mau = m; }
void main(){ PhanSo c = 7; }
62
UPDATES IN C++
(Keywords “explicit” and “delete”)
An easy-misleading example
class MyString {
wstring strBuf;
public:
explicit MyString(int
MyString(int n) {strBuf.assign(n,
n) {strBuf.assign(n, ‘ ’);} ‘ ’);}
MyString(const wchar_t *str) {strBuf = str;}
};
static MyString myStr = ‘A’;

Character ‘A’ is 65, so constructor


MyString(int) will be automatically called and
we have a string with 65 “spaces”
Put keyword “explicit” in front of the first
constructor to prevent ‘A’ (65) from implicitly
casting to MyString with the 1st constructor 63
UPDATES IN C++
(Keywords “explicit” and “delete”)
How about “MyString myStr(‘A’)”
class MyString {
wstring strBuf;
public:
explicit MyString(int n) {strBuf.assign(n, ‘ ’);}
MyString(const wchar_t *str) {strBuf = str;}
MyString(char ch) = delete;
};
static MyString myStr = ‘A’;
To solve such statements, prevent the
constructor with a character from being
called by using the keyword “delete”

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

#define New solution:


INIT_MEMBER(CLASS) virtual \ create a root
class Rectangle : public class
RootClass* createObject(){return new CLASS;} INIT_MEMBER(Rectangle);
RootClass {

class RootClass { int Rx, Ry;


public: public:
RootClass() {} virtual int Area() final { return Rx * Ry; }
virtual ~RootClass() {} Rectangle(int X = 0, int Y = 0):Rx(X), Ry(Y) {}
necessary for typeid’s polymorhism

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

You might also like