Acum este 19 Apr 2018, 20:42

Ora este UTC + 2 [ DST ]




Scrie un subiect nou Răspunde la subiect  [ 1 mesaj ] 
Autor Mesaj
 Subiectul mesajului: [info]Basic C++ programming techniques
Mesaj nouScris: 06 Aug 2009, 07:45 
Neconectat
Internaut expert
Avatar utilizator

Membru din: 25 Mai 2009, 10:44
Mesaje: 112
Basic C++ programming techniques
Incepem o serie in care vom discuta despre diverse tehnici de baza privind programarea in limbajul C++.


In acest snippet vom vedea cum putem simula mecanismul de polimorfism in momentul compilarii (compile time), folosind sabloane (templates) si o tehnica numita CRT (curiously recurrent template).

In mod normal, polimorfism-ul apare la runtime si se bazeaza pe mecanismul functiilor virtuale.

Sa vedem un examplu trivial:
Cod:
// virtual .cpp
#include <iostream>

class Base
{
   public:
   
   virtual ~Base() {};
   
   virtual void func() = 0;
};

class Derived1 : public Base
{
   public:
   
   void func()
   {
      std::cout << "Hello from Derived1" << std::endl;
   }   
};

class Derived2 : public Base
{
   public:
   
   void func()
   {
      std::cout << "Hello from Derived2" << std::endl;
   }   
};


class Proxy
{
   public:
   Proxy(Base* param) : m_param(param) {}
   void SetParam(Base* param) { m_param = param; }
   void func() { if (m_param) m_param->func(); }
   
   private:
   Base* m_param;
};
   
int main()
{
   Derived1 myDerived1;
   Derived2 myDerived2;
   Proxy myProxy1(&myDerived1);
   myProxy1.func();
   Proxy myProxy2(&myDerived2);
   myProxy2.func();
   
   return 0;
}

Avem o clasa de baza denumita Base, din care deriveaza 2 clase Derived1 si Derived2.
In clasa de baza Base, avem declarata o functie membru virtual pura, numita func
Datorita faptului ca func este virtual pura, clasele derivate din Base vor trebui sa redefineasca functia func, altfel se va obtine o eroare la compilare.

Clasa Proxy are ca membru un pointer catre un obiect de tip Base (sau, evident, derivat din Base).

Daca compilam acest cod:
Cod:
g++ virtual.cpp -o virtual

obtinem urmatorul output:
Cod:
./virtual
Hello from Derived1
Hello from Derived2

Utilizarea functiilor virtuale aduce un grad mare de flexibilitate in design-ul programului, dar, aduce si un overhead: o indirectare in plus a apelului functiei virtuale prin tabelul de functii virtuale (vtable).
In marea majoritate a cazurilor, acest overhead este minor si poate fi ingnorat, dar, sunt aplicatii in care dorim performanta maxima si vrem sa eliminam acest overhead.

O solutie este utilizarea sabloanelor (templates) pentru a obtine un efect similar la compile time.
Sa vedem cum modificam exemplul precedent pentru a beneficia de aceasta tehnica.
Cod:
// crtp.cpp
#include <iostream>

template <typename T>
class Base
{
   public:
   
   virtual ~Base() {};
   
   void func()
   {
      (static_cast<T*>(this))->func();
   }
};

class Derived1 : public Base<Derived1>
{
   public:
   
   void func()
   {
      std::cout << "Hello from Derived1" << std::endl;
   }   
};

class Derived2 : public Base<Derived2>
{
   public:
   
   void func()
   {
      std::cout << "Hello from Derived2" << std::endl;
   }   
};

template <typename T>
class Proxy
{
   public:
   Proxy(Base<T>* param) : m_param(param) {}
   void SetParam(Base<T>* param) { m_param = param; }
   void func() { if (m_param) m_param->func(); }
   
   private:
   Base<T>* m_param;
};
   
int main()
{
   Derived1 myDerived1;
   Derived2 myDerived2;
   Proxy<Derived1> myProxy1(&myDerived1);
   myProxy1.func();
   Proxy<Derived2> myProxy2(&myDerived2);
   myProxy2.func();
   
   return 0;
}

Clasa Base este acum o clasa sablon dupa parametrul T
Sa analizam implementare functiei membru func in clasa Base
Cod:
void func()
{
   (static_cast<T*>(this))->func();
}

Aici, convertim pointerul this catre un pointer la tipul T (parametrul sablonului) si apelam functia func membra a tipului T. Ideea este faptul ca parametrul T este o clasa care are definita o functie membru numita func.
Bineinteles, vom avea grija sa instantiem corect sablonul Base

Sa analizam acum felul in care sunt declarate clasele derivate Derived1 si Derived2
Cod:
class Derived1 : public Base<Derived1>
{
   public:
   
   void func()
   {
      std::cout << "Hello from Derived1" << std::endl;
   }   
};

Clasa Derived1 nu e declarata ca fiind o clasa sablon, dar deriveaza din clasa sablon Base instantiata chiar dupa tipul Derived .
Aceasta constructie poate parea complet neintuitiva unui programator novice, de aceea constructia este numita:
curiously recurrent template

Observam acum ca functia membra func nu este declarata ca fiind virtuala in clasele derivate Derived1 si Derived2

Daca apelam functia func() pe un obiect de tipul Derived1 (sau Derived2) prin intermediul unui pointer sau referinte la o instanta a clasei de baza (Base<Derived1> sau Base<Derived2>), se va apela implementarea lui func() din clasa de baza:
Cod:
(static_cast<T*>(this))->func();

Dar, precum am vazut, in aceasta implementare noi convertim de fapt pointerul la instanta clasei de baza ((Base<Derived1> sau Base<Derived2>) catre un pointer de tipul paramtrului sablonului dupa care s-a facut instantierea (Derived1 sau Derived2)
Deci, ca efect, ajungem sa apelam implementarea lui func() din clasa derivata (Derived1 sau Derived2)

In acest caz, clasa Proxy este tot o clasa sablon care mentine ca membru un pointer catre Base<T>.
Clasa Proxy este instantiata in functia main dupa Derived1 si Derived2
complilare
Cod:
g++ crtp.cpp -o crtp

executie
Cod:
./crtp
Hello from Derived1
Hello from Derived2

Aceasta tehnica este folosita de catre multe framework-uri moderne scrise folosind C++, precum WTL, SmartWin, Loki ...
Este o tehnica de baza in programarea moderna in limbajul C++

_________________
Imagine
https://cosmen.wordpress.com


Sus
 Profil  
 
Afişează mesajele de la anteriorul:  Sortează după  
Scrie un subiect nou Răspunde la subiect  [ 1 mesaj ] 

Ora este UTC + 2 [ DST ]


Cine este conectat

Utilizatorii ce navighează pe acest forum: Niciun utilizator înregistrat şi 3 vizitatori


Nu puteţi scrie subiecte noi în acest forum
Nu puteţi răspunde subiectelor din acest forum
Nu puteţi modifica mesajele dumneavoastră în acest forum
Nu puteţi şterge mesajele dumneavoastră în acest forum
Nu puteţi publica ataşamente în acest forum

Căutare după:
Mergi la:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Translation/Traducere: phpBB România