PARTICULARITĂȚILE
ELABORĂRII
APLICAȚIILOR C++
Croitor Mihail
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
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);
Pointer la funcție:
exemplu
#include <stdio.h>
typedef void (*event_t)(void*, void*);
struct Button{
size_t x, y, width, height;
char text[255];
event_t OnClick;
};
void ButtonPressed(void* /*sender*/, void* /*arg*/){
puts("button pressed!");
}
int main(){
Button btn = {5, 5, 75, 30, "Press Me!", ButtonPressed};
btn.OnClick();
return 0;
}
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:
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; }
};
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:
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;
}
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#
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.
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);
Ș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.
Ș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.
Ș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!
С++11: tipuri automate
Cuvântul cheie auto
spune compilatorului
să determine tipul
variabilei in mod
automat, după valoare
auto val = 5;
С++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};
С++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;}
};
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;
}
С++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){}
Mulțumesc de atenție!

0.0 particularitatile programarii с++

  • 1.
  • 2.
    Cuprins  Pointer lafuncț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);
  • 4.
    Pointer la funcție: exemplu #include<stdio.h> typedef void (*event_t)(void*, void*); struct Button{ size_t x, y, width, height; char text[255]; event_t OnClick; }; void ButtonPressed(void* /*sender*/, void* /*arg*/){ puts("button pressed!"); } int main(){ Button btn = {5, 5, 75, 30, "Press Me!", ButtonPressed}; btn.OnClick(); return 0; }
  • 5.
    Moștenire Moștenirea este unmecanism, 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 depolimorfism 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 Ofuncț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țiaclasei 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 claseireprezintă 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(){ inti1 = 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 untip 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ântulcheie auto spune compilatorului să determine tipul variabilei in mod automat, după valoare auto val = 5;
  • 16.
    С++11: inițializatori A apărutposibilitatea 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 lambdapermit 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 Utilizareavalorii 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ă «pentrufiecare» 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){}
  • 20.