0% found this document useful (0 votes)
97 views14 pages

Polimorfism. Clase Abstracte.: Polimorfismul

This document discusses polymorphism and abstract classes in object-oriented programming. It defines polymorphism as an object's ability to react differently depending on its state or for different objects to behave differently to the same action. Polymorphism allows objects to respond differently to the same message. The document provides examples of polymorphism using geometric shapes like circles and squares that inherit from an abstract Shape class. Function overriding and virtual functions are discussed as ways to implement polymorphism.

Uploaded by

rcky22
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
97 views14 pages

Polimorfism. Clase Abstracte.: Polimorfismul

This document discusses polymorphism and abstract classes in object-oriented programming. It defines polymorphism as an object's ability to react differently depending on its state or for different objects to behave differently to the same action. Polymorphism allows objects to respond differently to the same message. The document provides examples of polymorphism using geometric shapes like circles and squares that inherit from an abstract Shape class. Function overriding and virtual functions are discussed as ways to implement polymorphism.

Uploaded by

rcky22
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 14

Polimorfism. Clase abstracte.

Polimorfismul
• A treia trasatura esentiala in POO, dupa abstractizarea datelor si mostenire

• O alta dimensiune a separarii intre interfata si implementare, intre CE si CUM

• Determina o mai buna lizibilitate a codului, organizare mai eficienta si


dezvoltarea de programe extensibile
Polimorfism
Definitia 1: Polimorfismul este proprietatea unei entitati de a reactiona diferit in functie
de starea sa.

Definitia 2: Polimorfismul este proprietatea care permite unor entitati diferite sa se


comporte diferit la aceeasi actiune.

Definitia 3: Polimorfismul permite unor obiecte diferite sa raspunda diferit la acelasi


mesaj.

Figuri geometrice
Point.h Shape.h (2)
#ifndef POINT_H class Circle:public Shape{
#define POINT_H private:
#include <iostream> Point c;
using namespace std; float r;

class Point{ public:


int x,y; Circle(Point c1, float r1):c(c1),r(r1){}
void draw(){cout<<"Circle::draw()";}
public: float area(){cout<<"Circle::area()";
Point():x(0),y(0){} return PI*r*r;}
Point(int x, int y):x(x),y(y){} float perimeter()
Point(const Point& p):x(p.x),y(p.y{} {cout<<"Circle::perimeter()"; return
Point(int x):x(x),y(0){ 2*PI*r;}
} ~Circle(){}
int getX(){ return x; } };
int getY(){ return y; }
~Point(){ }
}; Shape
#endif
+draw(): void
+area(): float
+perimeter(): float
<<destroy>>+Shape()
Shape.h (1)
#ifndef SHAPE_H
#define SHAPE_H
#include "Point.h"
#include <cmath> Circle
#include <iostream> -r: float
<<create>>+Circle(c1: Point, r1: float)
using namespace std; +draw(): void
+area(): float
+perimeter(): float
const double PI=3.14; <<destroy>>+Circle()

class Shape{
public:
void draw()
{cout<<"Shape::draw()"<<endl;}
-c Point
float area()
{cout<<"Shape::area()"<<endl; return -x: int
0;} -y: int

float perimeter() <<create>>+Point()


{cout<<"Shape::perimeter()"<<endl; <<create>>+Point(x: int, y: int)
<<create>>+Point(p: Point)
return 0;} <<create>>+Point(x: int)
~Shape(){} +getX(): int
+getY(): int
}; <<destroy>>+Point()
Shape

Shape.h (3) +draw(): void


class Square:public Shape{ +area(): float
private: +perimeter(): float
<<destroy>>+Shape()
Point leftUp, rightDown;

public:
Square(Point p1, Point
p2):leftUp(p1), rightDown(p2){}
Square

void draw()
<<create>>+Square(p1: Point, p2: Point)
{cout<<"Square::draw()"<<endl;} +draw(): void
+area(): float
float area() +perimeter(): float
{cout<<"Square::area()"<<endl; <<destroy>>+Square()
float l= abs((float)(leftUp.getX()-
rightDown.getX()));
return l*l;}

float perimeter(){ -leftUp


cout<<"Square::perimeter()"<<endl; Point
return 4*abs((float)(leftUp.getX()- -rightDown
rightDown.getX()));} -x: int
-y: int

~Square(){} <<create>>+Point()
}; <<create>>+Point(x: int, y: int)
<<create>>+Point(p: Point)
#endif <<create>>+Point(x: int)
+getX(): int
+getY(): int
Test.cpp <<destroy>>+Point()
#include "Shape.h" 25π

void printArea(Shape& x){ 5


cout<<x.area()<<endl; 1
}

int main(){ 1
Shape* x1 = new Circle(Point(1,2),5);
Point p1(0,0), p2(1,1);
Shape* x2 = new Square(p1, p2);
printArea(*x1);
printArea(*x2);
return 0; Motivul?
• Legarea (binding) –conectarea
unui apel al unei functii la corpul
Realitatea…. functiei
• Legarea timpurie (early si adrese ale clasei de baza
binding) – stabilirea la momentul (referinte sau pointeri)
compilarii a metodelor care vor fi
apelate (compilatoare C) • La folosirea obiectelor transmise
prin valoare - object slicing la
• Solutia? upcasting
Object slicing
• Legarea intarziata (late binding, • Diferenta intre transmiterea prin
dynamic binding, runtime valoare/ transmiterea prin adresa
binding) – stabilirea doar la
momentul executiei a metodelor • Este recomandata transmiterea de
care vor fi apelate – functii adrese (au aceesi dimensiune)…
virtuale altfel, de obicei obiectele
derivate sunt “mai mari” decat
• Compilatorul nu va sti tipul obiectele clasei de baza
actual al obiectului, dar insereaza
cod care determina corpul corect • Cand se face upcast la un obiect
al functiei al clasei de baza – obiectul este
Functii virtuale “decupat” astfel incat ramane
• Declaratia doar partea comuna cu obiectele
virtual <antet_functie> clasei de baza

– Declaratia unei functii


virtuale se face o singura
data, in clasa de baza, ea
ramanand virtuala in
clasele derivate

–Daca o functie este


declarata virtuala in clasa
de baza si este suprascrisa
intr-o clasa derivata, are
loc legarea intarziata =
apelul metodei
corespunzatoare depinde
de tipul actual al
obiectului apelant
• CONSTRUCTORII
– NU pot fi virtuali (ei Persoana.h
instaleaza VPTR) #ifndef PERSOANA_H
#define PERSOANA_H
#include <cstring>
• DESTRUCTORII #include <cstdio>
– POT fi virtuali si in unele #include <iostream>
situatii chiar TREBUIE using namespace std;
sa fie virtuali
class Persoana{
protected:
• Legarea intarziata are loc numai char* nume;
cand se folosesc functii virtuale int varsta;
public: print(*p);
Persoana(char* n, int v){ delete(p);
nume=new char[strlen(n)+1]; system("pause");
strcpy(nume,n); return 0;
varsta=v;} Persoana(const };
Persoana& p){ #include "Persoana.h"
nume=new char[strlen(p.nume)+1]; #include <iostream>
strcpy(nume,p.nume); using namespace std;
varsta=p.varsta; }
virtual char* toString(){ void print (Persoana& p){
char* aux=new char[25] cout<<p.toString()<<endl;
sprintf(aux,"%s %d", nume,varsta); }
return aux;}
~Persoana(){ int main(){
if (nume) delete [] nume;} Persoana* p= new
}; Student("Ioana",21,"Informatica");
print(*p);
class Student:public Persoana{ delete(p);
char* facultate; return 0;
public: };
Student(char* n, int v, char*
f):Persoana(n,v){
facultate=new char[strlen(f)
+1]; …………………………………………
strcpy(facultate,f); Object slicing
} faculte?
…………………………………………
…………………………………………
Student(const Student& s):Persoana(s){ …………………………………………
facultate=new char[strlen(s.facultate)+1]; …………………………………………
strcpy(facultate,s.facultate); …………………………………………
Destructor virtual facultate???
}
#ifndef PERSOANA_H
char* toString(){
#define PERSOANA_H
char* aux = new char[30];
#include <cstring>
sprintf(aux,"%s %d %s",nume,
#include <cstdio>
varsta,facultate);
return aux;
class Persoana{
}
protected:
char* nume;
~Student(){
int varsta;
if (facultate)
delete [] facultate;
public:
}
Persoana(char* n, int v){
};
nume=new char[strlen(n)+1];
#endif strcpy(nume,n);
varsta=v;
Test.cpp }
#include "Persoana.h"
#include <iostream> virtual char* toString(){
Object slicing
using namespace std; char* aux=new char[25];
sprintf(aux,"%s %d", nume,
void print (Persoana p){ varsta);
cout<<p.toString()<<endl; return aux;
} }

int main(){ virtual ~Persoana(){


Persoana* p= new if (nume)
Student("Ioana",21,"Informatica"); delete [] nume;
}
};

Mecanismul
Obiect
VPTR

virtual_method1
virtual_method2
Virtual Method ...
Dispatch Table
(VTABLE)

• Fiecare clasa care are cel putin o


metoda virtuala are o data
membra ascunsa – pointer la {cout<<"Shape::draw()"<<endl;}
tabela functiilor virtuale – virtual float area()
{cout<<"Shape::area()"<<endl; return 0;}
contine adresele functiilor virtual float perimeter()
virtuale pentru clasa {cout<<"Shape::perimeter()"<<endl;return 0;}
corespunzatoare virtual ~Shape(){}
};
• Cand se face un apel folosind un
pointer sau o referinta la un astfel
de obiect, compilatorul genereaza class Circle:public Shape{
cod care dereferentiaza pointerul private:
spre tabela de functii virtuale a Point c;
clasei si face un apel indirect float r;
// const double PI=3.14;
folosind adresa functiei membre public:
a clasei din tabela functtilor Circle(Point c1, float r1):c(c1),r(r1){}
virtuale void draw(){cout<<"Circle::draw()";}
&Circle::draw float area(){cout<<"Circle::area()"; return
Circle &Circle::perimete PI*r*r;}
Shape* vptr r
&Circle::area float perimeter(){cout<<"Circle::perimeter()";
&Square::draw
return 2*PI*r;}
Square
vptr &Square::perimeter
~Circle(){}
};
&Square::area
Circle
vptr &Circle::draw class Square:public Shape{
&Circle::perimete
private:
r Point leftUp, rightDown;
&Circle::area
public:
• . Un obiect al unei clase derivate Square(Point p1, Point p2):leftUp(p1),
care a suprascris (override) rightDown(p2){}
implementarea unei metode void draw(){cout<<"Square::draw()"<<endl;}
virtuale din clasa de baza, are float area(){cout<<"Square::area()"<<endl;
float l= abs(leftUp.getX()-
pointerul VPTR indicand spre o rightDown.getX());
VTABLE diferita de a clasei de return l*l;}
baza, unde inregistrarea float perimeter()
corespunzatoare acelei metode {cout<<"Square::perimeter()"<<endl;
contine adresa functiei return 4*abs(leftUp.getX()-
rightDown.getX());
suprascrise }
~Square(){}
• Shape – metodele ar trebui sa fie };
virtuale… #endif

Test.cpp
Shape.h (versiunea 2) #include "Shape.h"
#ifndef SHAPE_H
#define SHAPE_H void printArea(Shape& x){
#include <cmath> cout<<x.area()<<endl;
#include <iostream> }
#include "Point.h"
using namespace std; int main(){
Shape* x1 = newCircle(Point(1,2),5);
const double PI=3.14; Point p1(0,0), p2(1,1);
class Shape{ Shape* x2 = new Square(p1, p2);
public: printArea(*x1);
virtual void draw() printArea(*x2);
return 0; – Oride reprezentare
} partajata (atribut comun)
25π – Orice functie membra
comuna (comportament
5 comun)
1
• O clasa abstracta nu are
instante!!!! (dar se pot defini
1 pointeri sau referinte la astfel de
clase)

• Are functii virtuale pure


Functii virtuale pure
• Declarare:
Shape.h
virtual <tip_returnat> <nume>(<lpf>)=0;
#ifndef SHAPE_H
#define SHAPE_H
#include "Point.h" •Mecanism:
#include <cmath> – Compilatorul rezerva un
#include <iostream> slot in VTABLE, dar nu
pune nici o adresa in acel
using namespace std;
slot – VTABLE nu va fi
const double PI=3.14; completa chiar daca
exista o singura functie
class Shape{
public:
“dummy code” virtuala pura
virtual void draw()
{cout<<"Shape::draw()"<<endl;} • Clasa abstracta pura – are numai
virtual float area() functii virtuale pure = interfata
{cout<<"Shape::area()"<<endl; return 0;} Clase concrete care mostenesc
virtual float perimeter() clase abstracte
{cout<<"Shape::perimeter()"<<endl; return 0;}
virtual ~Shape(){} • O clasa concreta care mosteneste
}; interfata publica a clasei
abstracte

• O clasa concreta se doreste sa


aiba instante

• Suprascrie metodele abstracte


(pure) pentru a furniza
implementari concrete specific
Clase abstracte reprezentarii proprii, altfel devine
• O clasa abstracta foloseste ca la randul sau o clasa abstracta
baza pentru o colectie de clase
derivate - prezinta o interfata • Shape – interfata – descrie
pentru clasele derivate comportamentul comun tuturor
figurilor geometrice
• Ea furnizeaza: Shape.h (versiunea 3)
– O interfata comuna #ifndef SHAPE_H
publica (functii virtuale #define SHAPE_H
#include <cmath>
pure)
#include <iostream>
#include "Point.h"
using namespace std; Shape
const double PI=3.14;
class Shape{ +draw(): void
public: +area(): float
virtual void draw()=0; +perimeter(): float
virtual float area()=0; <<destroy>>+Shape()
virtual float perimeter()=0;
virtual ~Shape()=0;
};
Avantajele polimorfimsului
Shape::~Shape(){} • Functii polimorfice
void printArea(Shape& s){
cout<<s.area()<<“ “;
Destructor virtual pur – are }
nevoie intotdeauna de corp vid
• Structuri de date polimorfice
– containere cu diferite
tipuri de elemente (fara
void* !!!)
Vector cu elemente generice
Test.cpp Array
#include "Shape.h" <<CppSynonym>> TElem
<<CppTypedef>> -elem
-n: int
int main(){ PElem
+equals(: PElem): int
Shape* s[3]; +toString(): char
<<create>>+Array(n1: int)
Point center(2,3); +add(p: PElem): void
<<destroy>>+TElem() +getElem(pos: int): PElem
s[0]=new Circle(center,4); +setElem(p: PElem, pos: int): void
Point lU(2,2), rD(5,5); +length(): int
s[1]= new Square(lU,rD); +remove(pos: int): void
<<destroy>>+Array()
s[2]=new Circle(lU,7);
for(int i=0;i<3;i++)
cout<<s[i]->area()<<endl; Integer Person

for(int i=0;i<3;i++) -i: int -name: char


delete s[i]; <<create>>+Integer(n: int) <<create>>+Person(n: char)
+toString(): char +toString(): char
+equals(p: PElem): int +equals(p: PElem): int
return 0; <<destroy>>+Integer() <<destroy>>+Person()
}

s Element.h
#ifndef ELEM_H
#define ELEM_H
class TElem;
typedef TElem* PElem;

class TElem{
public:
virtual int equals(PElem)=0;
Reprezentarea UML – clase virtual char* toString()=0;
abstracte virtual ~TElem(){};
};
#endif #ifndef PERSON_H
#define PERSON_H

<<CppSynonym>> TElem #include "Element.h"


<<CppTypedef>>
PElem
+equals(: PElem): int class Person:public TElem{
+toString(): char
<<destroy>>+TElem()
char* name;
public:
Person(char* n){
Integer.h name=new char[strlen(n)+1];
#ifndef INTEGER_H strcpy(name,n);
#define INTEGER_H }
#include <cstdio>
#include <cstring>
#include "Element.h" char* toString(){return name;}
using namespace std;
int equals(PElem p){
class Integer:public TElem{ return strcmp(name, ((Person*)p)-
private:
int i; >name)==0;
public: }
Integer(int n=0):i(n){}
~Person(){ delete [] name;}
char* toString(){ };
char* buf=new char[3];
sprintf(buf,"%d",i);
return buf;} #endif

int equals(PElem p){ return i==((Integer*)p)-


>i;} TElem
~Integer(){}
}; +equals(: PElem): int
#endif +toString(): char
<<destroy>>+TElem()

<<CppSynonym>> TElem
<<CppTypedef>>
PElem
+equals(: PElem): int
+toString(): char Person
<<destroy>>+TElem()
-name: char
<<create>>+Person(n: char)
+toString(): char
+equals(p: PElem): int
<<destroy>>+Person()
Integer
-i: int
<<create>>+Integer(n: int)
+toString(): char
+equals(p: PElem): int
<<destroy>>+Integer()
Array.h
#ifndef ARRAY_H
#define ARRAY_H
Person.h
#include "Element.h"

class Array{
PElem* elem;
int n;
public:

Array(int n1){elem = new PElem[n1]; n=0;}

void add(PElem p){elem[n++]=p;}

PElem getElem(int pos){return elem[pos];}

void setElem(PElem p, int pos){elem[pos]=p;}

int length(){return n;}

void remove(int pos){elem[pos]=elem[--n];}

~Array(){for(int i=0;i<n;i++)
delete elem[i];
delete [] elem;}
};
#endif

Array
<<CppSynonym>> TElem
<<CppTypedef>> -elem
-n: int
PElem
+equals(: PElem): int <<create>>+Array(n1: int)
+toString(): char +add(p: PElem): void
<<destroy>>+TElem() Diamond inheritance
+getElem(pos: int): PElem
+setElem(p: PElem, pos: int): void
TestArray.cpp class Right:public Top{
+length(): int
protected:
class Left:public Top{

#include "Integer.h" +remove(pos: int): voidint z; protected: int y;


public: Right(int x1, int
<<destroy>>+Array() public: Left (int x1, int
#include "Person.h" z1):Top(x1){z=z1;} y1):Top(x1){y=y1;}
#include "Array.h" }; };
#include <iostream> #ifndef DI_H
using namespace std; #define DI_H

void print(Array& a){ class Top{
protected: int x;
for(int i=0;i<a.length();i++) public:Top(int x1){x=x1;}
cout<<a.getElem(i)->toString()<<" "; };
cout<<endl;
class Bottom: public Left, public Right{
}
int w;
public:
int main(){
Array a(4);
Bottom(int x1, int y1, int z1, int w1):
a.add(new Integer(3));
/*Top(x1),*/Left(x1, y1), Right(x1, z1)
a.add(new Integer(4));
{w=w1;}//Top is not a base class of Bottom
a.add(new Integer(5));
a.add(new Person("Adriana"));
friend ostream& operator<<(ostream& os,
print(a);
Bottom& b){
return 0;
return os<<" "<<b.y<<" "<<b.z<<"
}
"<<b.w<<endl;//x …ambiguous
};
Mostenire multipla #endif
Diamond inheritance
Diamond inheritance
#include "DiamondInheritance.h"
int main(){ int y;
public:
Left (int x1, int y1):Top(x1){y=y1;}
Bottom b(1,2,3,4); };
cout<<sizeof(b)<<endl; class Right: virtual public Top{
cout<<b; protected:
return 0; int z;
} public:
Right(int x1, int z1):Top(x1){z=z1;}
};

class Bottom: public Left, public Right{


int w;
public:
True diamond inheritance //ultima dintre clasele derivate va trebui sa
initializeze clasa de baza, altfel vor exista
ambiguitati (Left sau Right?)

Bottom(int x1, int y1, int z1, int w1): Top(x1),


Left(0, y1), Right(0, z1){w=w1;}

friend ostream& operator<<(ostream& os,


Bottom& b){
return os<<b.x<<" "<<b.y<<" "<<b.z<<"
"<<b.w<<endl;//x poate fi tiparit...virtual
}
};
#endif

True diamond inheritance


#include "DiamondInheritance.h"

int main(){

Bottom b(1,2,3,4);
cout<<sizeof(b)<<endl;
cout<<b;
return 0;
}

Mostenire virtuala
#ifndef DI_H
#define DI_H True diamond inheritance
#include <iostream>
using namespace std;
• Cand b:Bottom este instantiat,
obiectul b va aparea astfel:
class Top{
protected:
int x; Left
public:
Top(int x1){x=x1;} Right
virtual ~Top(){}//all base classes must have
virtual destructors
};
Bottom
class Left: virtual public Top{ Top
protected:
• Subobiectele Left si Right are
fiecare cate un pointer la acelasi
subobiect partajat Top

• Cand apare mostenirea multipla,


un obiect al clasei derivate se
comporta ca si cum ar avea mai
multi VPTR, cate unul pentru
fiecare clasa de baza directa

Concluzii
• Mostenirea multipla –
nerecomandata –
– solutia Java –
mostenire simpla si
implementare de
interfete multiple

• Mecanismul functiilor
virtuale – de ce nu implicit?
– motive de eficienta

You might also like