SDA Lucrarea 2

De la WikiLabs
Versiunea din 8 martie 2017 22:28, autor: Radu Hobincu (Discuție | contribuții) (Clasa și obiectul)

În acest laborator se introduc noțiuni noi de Programare Orientată pe Obiecte: clasa, obiectul, metoda, constructorul, destructorul, namespace și template.

Structurile in C

Ne amintim că în C, o structură e definită printr-un nume, care reprezintă numele tipului de date, precum și un număr de câmpuri, adică una sau mai multe varibile, definite prin tip și nume, ce reprezintă datele componente ale structurii:

struct Person {
    char name[128];
    uint8_t age;
    char cnp[14];
    char address[256];
};

Structura Person este un tip de dată, prin urmare putem declara și utiliza variabile de tipul acestei structuri:

int main() {
    struct Person somePerson;
    return 0;
}

În codul de mai sus, s-a declarat o varibilă de tip struct Person, cu numele somePerson. Prin definirea unei variabile de tipul structurii, de fapt s-au definit în mod automat toate variabilele membre ale acesteia: name, age etc. Având o variabilă de tipul structurii, membrii acesteia se pot accesa cu operatorul .:

int main() {
    struct Person somePerson;
    somePerson.age = 20;
    return 0;
}

Dacă avem un pointer la o structură, putem accesa membrii acesteia în două moduri:

  1. Prin dereferențierea pointerului (adică obținerea valorii de la adresa respectivă), folosind operatorul *.
  2. Prin utilizarea operatorului -> care este analog operatorului ., dar se folosește cu variabile de tip pointer-la-structură, în loc de variabile de tip structură:
int main() {
    struct Person somePerson;
    somePerson.age = 20;

    struct Person * somePersonPointer = &somePerson;

    /* Varianta 1 */
    strcpy((*somePersonPointer).name, "Andrei");

    /* Varianta 2 */
    strcpy(somePersonPointer->name, "Andrei");

    return 0;
}

Noțiuni introductive de Programare Orientată pe Obiecte (POO)

Ideea de bază de la care a pornit paradigma POO este faptul că o structură poate modela orice obiect din jurul nostru, pentru că orice obiect are proprietăți, care pot fi stocate în variabile membre ale structurii. Aceste obiecte pot fi atât fizice (o minge, un șurub, un tranzistor, o sticlă cu apă), cât și obiecte abstracte (un număr natural, un număr complex, o funcție matematică sau un sortator de valori în virgulă mobilă). Fiecare din aceste obiecte au un set de proprietăți care pot fi identificate. Spre exemplu, o minge are o anumită culoare, o anumită formă, un anumit volum, o anumită masă și un anumit proprietar. Sigur, există și alte proprietați pe care o minge le poate avea (de exemplu materialul de fabricație sau gazul cu care este umplută), dar în general când analizăm un obiect, ne gândim exclusiv la proprietățile relevante pentru aplicația noastră (de exemplu dacă avem o bază de date cu angajați, probabil nu ne înteresează culoarea părului fiecărui angajat, dar ne interesează vârsta și vechimea acestuia). Putem observa că o parte din proprietăți sunt constante pe toată durata de viață a obiectului (cum ar fi culoarea, masa și forma), acestea numindu-se imutabile, iar altele se pot schimba pe perioada de viață a obiectului (de exemplu proprietarul).

Clasa și obiectul

Haideți să definim o structură care să modeleze obiecte de tip minge:

enum Color {
    WHITE,
    RED,
    BLUE,
    GREEN
};

enum Shape {
    SPHERE,
    OVOID
};

struct Ball {
    enum Color color;
    enum Shape shape;
    float volume;
    float mass;
    Person owner;
};

Pentru a modela complet obiecte reale însă, mai lipsește ceva. Obiectele din lumea reală nu au doar proprietăți, ci și interacționează între ele. Acțiunile se modelează în programare prin funcții, acestea fiind cele care prin execuție modifică proprietățile obiectelor asupra cărora acționează. Să spunem că o minge își poate schimba proprietarul. Definim deci următoarea funcție:

void changeBallOwner(Ball * ball, Person newOwner) {
    ball->owner = newOwner;
}

Se vede aici că funcția changeBallOwner se apelează întotdeauna pentru un obiect de tip Ball. De altfel, această funcție nu are sens decât în contextul unei mingi (altfel spus, trebuie să am o minge ca să-i pot schimba proprietarul). Prin urmare, o metodă mai bună de reprezentare a obiectelor de tip Ball ar fi ca și funcția changeBallOwner să facă parte din structură, ca și proprietățile acesteia. Astfel, C++ introduce o modificare foarte simplă structurilor din C: acestea pot acum să conțină și funcții:

enum Color {
    WHITE,
    RED,
    BLUE,
    GREEN
};

enum Shape {
    SPHERE,
    OVOID
};

struct Ball {
    enum Color color;
    enum Shape shape;
    float volume;
    float mass;
    Person owner;

    void changeOwner(Person newOwner) {
        owner = newOwner;
    }
};

Se observă următoarele modificări:

  1. am redenumit funcția din changeBallOwner în changeOwner, pentru că funcția făcând parte din structura Ball, este evident pentru ce tip de obiect se apelează.
  2. a dispărut primul argument al funcției, cel de tip Ball, deoarece această funcție se va apela acum pentru un obiect de tip Ball folosind operatorul de acces la membri, așa cum se accesează și proprietățile:
int main() {
    Ball myBall;
    Person me;
    myBall.changeOwner(me);
    return 0;
}