Tuesday, December 29, 2015

Limbajul C++. Clonarea obiectelor folosind metodele virtuale si constructorul de copiere


Realizarea unei clone a unui obiect presupune crearea unui obiect nou, cu existenta independenta de cel clonat, care ocupa in memorie un spatiu distinct de cel clonat dar care are toate atributele si metodele identice cu ale celui clonat.

Mecanismul urmator foloseste constructorul de copiere si o metoda declarata virtuala, care este supracrisa in clasa derivata. Declararea virtuala este necesara pentru apelul corect al metodelor: metoda Clone va fi cautata intai in clasa derivata, indiferent de scenariu - fie ca variabila are tipul clasei de baza sau cel al clasei derivate.

Stim ca o variabila initializata cu o instanta a clasei derivate are si tipul clasei de baza (invers nu!)

Suprascrierea metodei implica prezervarea aceleiasi semnaturi (nume, argumente, tip de return) dar o implementare diferita in clasa derivata.


Clasa de baza numita Base  are un membru protected (pentru a putea fi accesat prin constructorul de copiere si din clasa derivata), constructorul explicit, constructorul de copiere, metoda virtuala Clone() ce va fi suprascrisa in clasa Derivat. Destructorul clasei de baza este declarat virtual.

Metodele getter din ambele clase au rolul de a permite verificarea clonarii - daca s-a facut in mod corect, cu transmiterea informatiei din membrii protected si private ai obiectului clonat la obiectul-clona.

De remarcat ca metoda Clone() intoarce, prin definitie, un pointer la tipul Base.

Prin urmare, chiar daca este apelata metoda din clasa Derivat (si se cloneaza obiectul apartinand acestei clase), este necesara o operatie cast  a pointerului (Base *) la tipul (Derivat *),  pentru a putea accesa membrul obiectului clonat apartinand clasei derivate.

Codul urmator exemplifica aceste situatii: 1) clonarea unui obiect din clasa Derivat, generat dinamic si 2) clonarea unui obiect din clasa Base. Spatiile alocate dinamic se sterg la final cu operatorul delete.

// mecanismul de clonare

#include <iostream>

using namespace std;

class Base
{
      protected:
      int _p;
      
      public:
      
      Base(int p = 0) {_p = p;}
      Base(const Base &src) {_p = src._p;}
      
      virtual ~Base() {cout <<"Distrugerea instantei tip Base.\n";}
      virtual Base * Clone() {cout << "\nAlpha!"; return new Base(*this);}
      
      int Getp() {return _p;}
};

class Derivat : public Base
{
      int _q;
      
      public:
      Derivat(int p = 0, int q = 0) : Base(p), _q(q) {}
      Derivat(const Derivat &src) {_p = src._p; _q = src._q;}
      
      ~Derivat() {cout <<"Distrugerea instantei tip Derivat.\n";}

      Base * Clone() {cout << "\nBeta!"; return new Derivat(*this);}
      
      int Getq() {return _q;}
};

int main()
{
    Base * ptr = new Derivat(128, 1024);
    Base * ptr1 = ptr->Clone();
    
    cout <<"\n" <<ptr1->Getp();
    cout <<"\n" <<((Derivat*)ptr1)->Getq(); // cast la tipul (Derivat *)
    cout <<"\n";
    
    Base * ptr2 = new Base(64);
    Base * ptr3 = ptr2->Clone();
    cout << "\n" <<ptr3->Getp();
    cout <<"\n\n";
    
    delete ptr; // este apelat destructorul clasei derivate
    delete ptr1; // este apelat destructorul clasei derivate
    
    delete ptr2;
    delete ptr3;
    
    return 0;
}




    

No comments:

Post a Comment