This shows you the differences between two versions of the page.
poo-is:laboratoare:08 [2020/09/29 14:14] eduard.ciurezu [Clase si Functii Abstracte] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 08: Mostenire multipla. Clase si functii abstracte. Interfete ===== | ||
- | In cadrul acestui laborator, vom discuta despre **mostenirea multipla** si ambiguitatile care pot aparea o data cu aceasta, despre **clasele si functiile abstracte** si despre **interfete**, cu ajutorul carora vom reusi sa aprofundam cunostintele legate de derivarea claselor si suprascrierea metodelor acestora. | ||
- | |||
- | Ca referinte externe, recomandam urmatoarele sectiuni din [[https://discourse-production.oss-cn-shanghai.aliyuncs.com/original/3X/2/3/2380479dcb8e375425884a10da232730bbc7f88d.pdf|Absolute C++]]: | ||
- | * Abstract Classes and Pure Virtual Functions (pag. 671-673) | ||
- | * Separate Interface and Implementation (pag. 264-265) | ||
- | |||
- | ====== Mostenire Multipla ====== | ||
- | Spre deosebire de multe alte limbaje de programare orientate-obiect, C++ permite **mostenirea multipla** (o clasa poate fi derivata din mai multe clase de baza). | ||
- | <note>In acest caz, la declararea clasei derivate nu se specifica o singura clasa de baza, ci o succesiune de clase de baza, separate prin virgula, avand in fata specificatorii de acces.</note> | ||
- | <code>class C:public A, public B</code> | ||
- | <note>In candrul mostenirii multiple, **constructorii** claselor de baza vor fi apelati in ordinea enumerarii, iar **destructorii** vor fi apelati in ordine inversa.</note> | ||
- | |||
- | ===== Problema Diamantului ===== | ||
- | Desi mostenirea multipla pare a fi un procedeu util, aceasta poate duce la multe ambiguitati, cea mai mare dintre acestea fiind **Problema Diamantului** (numita si **“death diamond”**). Sa consideram urmatoarea ierarhie de clase: | ||
- | |||
- | {{ :poo-is:laboratoare:ierarhie-clase-diamant.png?300 |}} | ||
- | |||
- | In acest exemplu, avem o clasa de baza numita **LivingThing** avand metoda **breathe()**. Clasele **Animal** si **Reptile** mostenesc clasa **LivingThing** si suprascriu in moduri diferite metoda **breathe()**. Clasa **Snake** mosteneste ambele clase, **Animal** si **Reptile**, insa nu suprascrie metoda **breathe()**. | ||
- | |||
- | <note important>In momentul de fata, daca apelam metoda **breathe()** din **Snake**, acesta nu va sti ce metoda sa apeleze, daca sa fie cea suprascrisa in clasa **Animal** sau cea suprascrisa in clasa **Reptile**.</note> | ||
- | |||
- | <note tip>Cum rezolvam insa Problema Diamantului? Folosind **derivarea virtuala**. | ||
- | <code>class Animal: virtual public LivingThing | ||
- | class Reptile: virtual public LivingThing</code></note> | ||
- | |||
- | Clasele de baza virtuale sunt utile in cadrul mostenirii multiple cand o serie de clase sunt derivate din aceeasi clasa de baza, iar aceasta urmeaza a fi clase parinte pentru o alta clasa. | ||
- | |||
- | Efectul acestei mosteniri virtuale nu este sesizat in clasele **Animal** si **Reptile**, ci se observa in urmatorul nivel de derivare, clasa **Snake**. | ||
- | |||
- | <note>Pentru a se crea un obiect de tip **Snake**, se vor apela constructorii claselor **Animal** and **Reptile**, dar se va apela o singura data constructorul clasei **LivingThing**, astfel **Snake** va avea o singura instanta a clasei **LivingThing**.</note> | ||
- | |||
- | ====== Clase si Functii Abstracte ====== | ||
- | |||
- | O metoda virtuala se numeste **abstracta (pura)** daca nu are implementare: | ||
- | <code>virtual tip_returnat metoda(lista parametrii) = 0;</code> | ||
- | <note>O clasa se numeste **abstracta** daca are cel putin **o metoda abstracta**.</note> | ||
- | |||
- | Uneori implementarea tuturor functiilor dintr-o clasa de baza nu poate fi realizata, deoarece nu stim cu certitudine implementarea acestora. Sa presupunem ca avem o clasa de baza **Shape**. Nu putem implementa metoda **draw()** in **Shape**, insa stim cu siguranta ca fiecare clasa derivata o sa aiba aceasta metoda implementata. | ||
- | |||
- | <code c++ Shape.cpp> | ||
- | #include <iostream> | ||
- | using namespace std; | ||
- | |||
- | //Clasa abstracta | ||
- | class Shape { | ||
- | //Membrii clasei | ||
- | public: | ||
- | //Functie abstracta | ||
- | virtual void draw() = 0; | ||
- | }; | ||
- | |||
- | //Clasa care mosteneste Shape si implementeaza draw | ||
- | class Circle: public Shape { | ||
- | public: | ||
- | void draw() { cout << "DRAW CIRCLE!" << endl; } | ||
- | }; | ||
- | |||
- | int main () { | ||
- | Circle c; | ||
- | c.draw(); //Se va afisa DRAW CIRCLE! | ||
- | return 0; | ||
- | } | ||
- | </code> |