Warning Nu esti autentificat. Te rog autentifica-te sau inregistreaza-te pentru a avea acces la toate facilitatile forumului.
SkullBox  
Decembrie 01, 2008, 07:19:29 pm
Bine ai venit, Vizitator. Trebuie să te autentifici sau să îţi creezi un cont.
Ai pierdut sau nu ai primit emailul care conţine codul de activare al contului?

Autentifică-te cu numele de utilizator, parola şi precizează durata sesiunii.
Noutăţi: Blogu' lu' Myky
 
 SkullBoxDirector webTutoriale  Pagina principală   Ajutor Caută Autentificare Creează un cont  
Pagini: [1]
  Imprimă  
Subiect: Compile time polymorphism  (Citit de 326 ori)
0Utilizatori şi 1 Vizitatori
astan
Skullbox user
Global Moderator
*
Deconectat Deconectat

Gen: Bărbat
Mesaje: 308


Compile time polymorphism, Octombrie 04, 2008, 09:37:25 pm

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

Compilare:
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++.
Memorat
SkullAds
Ecspert
ReclAmator
* * * * *
Google AdSense

Gen: Bărbat
Mesaje: Multe

Reclama AdSense,
 

 
   


Pagini: [1]
  Imprimă  
 
Schimbă forumul:  

Creat cu MySQL Creat cu PHP Ethical hacking and programming community Director web romanesc cu inscriere gratuita Validat cu XHTML 1.0! Validat cu CSS!
IPFind, FAQDB, LAMP.ro, Good Proxy, Aberez.EU, RoFreeSBIE, ShockingSoft.com, HostVision, Invatam.net, PC Troubleshooting, Curs valutar online
Powered by SMF 1.1.7 | SMF © 2006-2008, Simple Machines LLC
Traducerea în limba română © 2006-2007 www.smf.ro