Kód Delegáti v CPP

Z CHWiki

Přejít na: navigace, hledání

Implementace delegátu v C++. Nejde o to, aby byly přesně jako v C#, ale aby se jim co nejvíce podobaly. Další výhodou je, že je možné mít v delegátovi jak standardní funkce, tak i metody. Bohužel neumožňují mít ve funkci víc jak 1 parametr. Na konci je příklad použití.

[editovat] Zdrojový kód

#pragma once

// Tady si muzes priradit vlastni typ pointeru pro potomky tridy ICall
// Napr.: #define _DELEG_PTR_TYPE(type) CSmartPointer< type >

#define _DELEG_PTR_TYPE(type) type*

// Zde si nastav tridu, ze ktere bude ICall dedit
// Napr.: #define _DELEG_CALL_INHERIT : public CSharedObject

#define _DELEG_CALL_INHERIT

// Tohle zakomentuj, pokud nechces, aby se na pointery volalo delete

#define _DELEG_ALLOW_DELETE


/**
    Obecna funkce s parametrem
**************************************************************************************************/
template<class Param = void>
class ICall _DELEG_CALL_INHERIT
{
public:
    virtual void Call(Param) = 0;
};

/**
    Ukazatel na funkci s volitelnym parametrem
**************************************************************************************************/
template<class Param = void>
class CFunctionCall : public ICall<Param>
{
public:
    typedef void (*FUNC)(Param);
    CFunctionCall(const FUNC f): m_f(f) {}
    virtual void Call(Param p) { return m_f(p); }

private:
    FUNC m_f;
};

/**
    Ukazatel na funkci specializovany pro parametr void
**************************************************************************************************/
template<>
class CFunctionCall<void> : public ICall<void>
{
public:
    typedef void (*FUNC)();
    CFunctionCall(const FUNC f): m_f(f) {}
    virtual void Call() { return m_f(); }

private:
    FUNC m_f;
};

/**
    Ukazatel na metodu s volitelnym parametrem
**************************************************************************************************/
template<class T, class Param = void>
class CMethodCall : public ICall<Param>
{
public:
    typedef void (T::*FUNC)(Param);
    CMethodCall(T *obj, const FUNC f): m_obj(obj), m_f(f) {}
    virtual void Call(Param p) { return (m_obj->*m_f)(p); }

private:
    T *m_obj;
    FUNC m_f;
};

/**
    Ukazatel na metodu specializovany pro parametr void
**************************************************************************************************/
template<class T>
class CMethodCall<T, void> : public ICall<void>
{
public:
    typedef void (T::*FUNC)();
    CMethodCall(T *obj, const FUNC f): m_obj(obj), m_f(f) {}
    virtual void Call() { return (m_obj->*m_f)(); }

private:
    T *m_obj;
    FUNC m_f;
};

/**
    Delegat - zapoudruje pole obecnych ukazatelu na funkci

    Inspirovano z C#.
**************************************************************************************************/
template<class Param = void>
class CDelegate
{
public:
    typedef _DELEG_PTR_TYPE(ICall<Param>) PCall;

#ifdef _DELEG_ALLOW_DELETE
    ~CDelegate() { Clear(); }
#endif

    void Clear()
    {
#ifdef _DELEG_ALLOW_DELETE
        for (std::vector<PCall>::iterator it = m_list.begin(); it != m_list.end(); it++)
            delete *it;
#endif
        m_list.clear();
    }

    void operator +=(PCall call)    { m_list.push_back(call); }
    void operator -=(PCall call)    { m_list.remove(call); }

    void operator ()(Param p)
    {
        for (std::vector<PCall>::iterator it = m_list.begin(); it != m_list.end(); it++)
            (*it)->Call(p);
    }

private:
    std::vector<PCall> m_list;
};

/**
    Delegat specializovany na parametr void
**************************************************************************************************/
template<>
class CDelegate<void>
{
public:
    typedef _DELEG_PTR_TYPE(ICall<>) PCall;

#ifdef _DELEG_ALLOW_DELETE
    ~CDelegate() { Clear(); }
#endif

    void Clear()
    {
#ifdef _DELEG_ALLOW_DELETE
        for (std::vector<PCall>::iterator it = m_list.begin(); it != m_list.end(); it++)
            delete *it;
#endif
        m_list.clear();
    }

    void operator +=(PCall call)    { m_list.push_back(call); }
    void operator -=(PCall call)    { m_list.remove(call); }
 
    void operator ()()
    {
        for (std::vector<PCall>::iterator it = m_list.begin(); it != m_list.end(); it++)
            (*it)->Call();
    }

private:
    std::vector<PCall> m_list;
};

[editovat] Použití bez parametru

void moje_funkce() {}

class Trida
{
public:
    void Metoda() {}
};

int main(...)
    ...
    CDelegate<> deleg;
    deleg += new CFunctionCall<>(moje_funkce);
    deleg += new CMethodCall<Trida>(&Instance, &Trida::Metoda);
    deleg(); // Zavola vsechny funkce
    ...

[editovat] Použití s libovolným parametrem (v tomto případě int)

void moje_funkce(int a) {}

class Trida
{
public:
    void Metoda(int a) {}
};

int main(...)
    ...
    CDelegate<int> deleg;
    deleg += new CFunctionCall<int>(moje_funkce);
    deleg += new CMethodCall<Trida, int>(&Instance, &Trida::Metoda);
    deleg(10); // Zavola vsechny funkce
    ...