2. Cuprins
Pointer la funcție
Moștenire
Funcții virtuale
Polimorfism în baza funcțiilor virtuale
Clase abstracte
Redefinire operatorilor
Obiecte funcționale
Șabloane
Polimorfism static
Specializare șabloanelor
Unele particularități ale standardului C++11
3. Pointer la funcție
Pointer la funcție este un pointer, care conține
adresa punctului de întrare în această funcție.
Declararea variabilei-pointer la funcție:
void (*pfunc)(double*, const size_t);
Declararea tipului pointer la funcție:
typedef void (*pfunc_t)(double*, const size_t);
5. Moștenire
Moștenirea este un mecanism, care permite
descrierea clasei noi (clasa copil, clasa
derivată) în baza unei clase existente (clasa de
bază, clasa părinte) cu păstrarea
funcționalității clasei de bază.
Moștenirea permite manipularea cu obiecte
de clasa derivata ca cu obiecte clasei de bază.
Pointer la obiectul clasei de bază poate referi
la obiectul clasei derivate. Afirmație inversă
este greșită.
class Base {
int value;
public:
Base(): value(0){}
int getValue() { return value; }
};
class Derived: public Base{
public:
Derived() : Base() {}
void setValue(int data) {
value = data;
}
};
Exemplu moștenirii:
6. Moștenire:
exemplu
class Entity{
protected:
std::string name;
Entity* parent;
public:
virtual std::string ToString() const = 0;
Entity* GetParent() const{ return parent; }
};
class Folder: public Entity{
std::list<Entity*> childs;
public:
Folder(std::string n, Entity* p)
: name(n), parent(p){}
std::string ToString() const { return name; }
};
7. Funcții virtuale
Funcție virtuală a clasei este o metodă,
care poate fi redefinită în clasa copil și în
dependența de situație se determină în
timpul executării aplicației care
realizarea concretă a funcției va fi
apelată.
Polimorfismul în baza funcţiilor virtuale
se numeste polimorfism dinamic.
Această proprietate printre altele permite
invocarea unei şi aceleiaşi funcţiei (fără
redeclararea/redefinirea) cu parametrii
actuali de diferite tipuri.
class Base{
public:
Base(): value(0){}
virtual void show() {
std::cout << "Base" << std::endl;
}
};
class Derived: public Base{
public:
Derived() : Base() {}
virtual void show() {
std::cout << «Derived" << std::endl;
}
};
Exemplu:
8. Funcții virtuale:
exemplu de polimorfism
class Base{
public:
Base(): value(0){}
virtual void show() { std::cout << "Base" << std::endl; }
};
class Derived: public Base{
public:
Derived() : Base() {}
virtual void show() { std::cout << "Derived" << std::endl; }
};
void print(Base* p) { p->show(); }
int main(){
Base* b = new Base();
Derived* d = new Derived();
print(b);
print(d);
return 0;
}
9. Funcții virtuale:
clase abstracte
O funcție virtuala poate fi declarata in clasa
fără definirea corpului ei. In acest caz funcția
se egalează cu zero si se numește funcția
virtuală pură sau funcția abstractă. Daca o
clasa conține cel puțin o funcție virtuala
pura, atunci aceasta clasa se numește clasa
abstracta.
Orice funcție abstractă se redefinește în
clasa-copil.
Clasele abstracte se utilizează în cazuri când
programator are nevoie de o mulțime de
clase cu comportament comun.
struct Shape{
virtual void Draw() = 0;
virtual void Hide() = 0;
};
struct Point: Shape{
virtual void Draw(){
// draw this point
}
virtual void Hide(){
// hide this point
}
};
Clase abstracte sunt asemănătoare
interfețelor din Java și C#
10. Redefinirea operatorilor
pentru comoditate, este utila
supraîncărcarea (redefinirea) unui
operator standard pentru o clasa.
Programul in acest caz devine mai
compact si mai clar.
Forma comuna pentru
supraincarcare este urmatoarea:
<return_type> operator <operator
_sign> (<operator_parametres>);
сlass int_pair{
int first, second;
public:
int_pair(int f = 0, int s = 0): first(f),
second(s) {}
bool operator == (const int_pair&
p) const {
return (first == p.first) && (second
== p.second);
}
};
bool operator != (const int_pair&
p1, const int_pair& p2){
return !(p1 == p2);
}
pentru a determina locul de declarare a
operatorului - in cadrul clasei, sau in afara
ei - întrebați-va, daca acest operator
schimba parametrii de intrare. Daca da,
atunci se recomanda declararea acestui
operator in clasa, dacă nu, atunci mai bine
declarați-l in afara clasei.
11. Obiecte funcționale
In declarația clasei poate fi
supraîncărcat operatorul (). Daca acest
operator este supraîncărcat, atunci
obiectele acestei clase obțin unele
proprietăți ale funcțiilor (ele pot fi
utilizate in același mod ca si funcții).
Aceste obiecte se numesc obiecte
funcționale sau functori.
Utilizarea functorilor este comoda
atunci când funcția trebuie sa aibă
"memorie", sau ca o alternativa
pointerilor la funcție.
// functor care socoate numărul de apeluri
class _swap{
static size_t counter = 0;
static void increment() { ++counter; }
public:
_swap(){}
void operator ()(int& a, int& b){
int tmp = a;
a = b;
b = tmp;
inc();
}
int getNrCalls() {return count; }
};
_swap swap;
int a = 3, b = 5;
swap(a, b);
12. Șabloane
Șablonul clasei reprezintă
un mecanism de generare a
familiei de clase cu
comportament comun
Șablonul funcției reprezintă
un mecanism de generare a
familiei de funcții cu
comportament comun
template<class TYPE>
void swap(TYPE& p1, TYPE& p2){
TYPE tmp = p1;
p1 = p2;
p2 = tmp;
}
Noțiunea șablonul funcției deseori se
asociază cu noțiunea de algoritm.
13. Șabloane:
polimorfism static
int main(){
int i1 = 3, i2 = 5;
float f1 = 1.2, f2 = 2.3;
double d1 = 1.003, d2
= 10;
swap(i1, i2);
swap(f1, f2);
swap(d1, d2);
return 0;
}
În exemplu dat, una si aceeași
denumirea funcției este utilizata
cu tipuri de date diferite.
Aceasta proprietate, realizată cu
ajutorul șabloanelor, se
numește polimorfism static,
deoarece determinarea
comportamentului funcției are
loc la etapa de compilare a
programului.
14. Șabloane:
specializarea șabloanelor
Pentru un tip de date
concret poate fi definită o
versiune specială a
șablonului.
template<>
void swap(int* a, int* b){
int tmp = *a;
*a = *b;
*b = tmp;
}
Dacă un șablon (și/sau specializarea lui)
nu se utilizează în codul sursă atunci la
etapa de compilare el nu se include în
codul binar!
15. С++11: tipuri automate
Cuvântul cheie auto
spune compilatorului
să determine tipul
variabilei in mod
automat, după valoare
auto val = 5;
16. С++11: inițializatori
A apărut posibilitatea
inițializării claselor
containeri cu ajutorul
listelor de inițializare.
class Array10{
int _val[10];
public:
Array10(std::initializer_list
<int> list);
};
Array10 a =
{1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
17. С++11: lambda-funcții
Expresii lambda permit
programatorilor să
accelereze scrierea
codului. Sub expresii
lambda înțeleg un mod
special de definirea
functorilor.
[](int x, int y) { return x + y; }
// то же, что и [](int x, int y) ->
int{ int result = x + y; return
result; }
struct sum{
int opertator()(int x, int
y){ return x+y;}
};
18. C++11: pointer nul
Utilizarea valorii 0 ca
pointer nul în unele
cazuri aducea la cod
periculos. Se recomandă
utilizarea cuvântului
cheie nullptr.
void test(int);
void test(char*);
int main(){
test(0); // ???
test(nullptr); // !!!
return true;
}
19. С++11: buclă «pentru fiecare»
int a[5] = {1, 2, 3, 4, 5};
for(auto& el: a){
++el;
}
for(auto el: a){
std::cout << el << " ";
}
Standard nou С++ propune o
formă nouă de bucla for:
for( type element:
collection){}