LINUX.ORG.RU

C++ callback


0

2

Не пишу на сабже, нужно что-то вроде следующего:

// A.h

class A {
  public:
    char makeMeFeelGood1();
    char makeMeFeelGood2();
    char makeMeFeelGood3();
};

// B.h

extern "C" {
  typedef char (A::*waitCallback)(void);
}

class B {
  public:
    void fun();
    void waitForever(waitCallback callback);
    A obj;
};

// B.cpp

void B::wait(waitCallback callback) {
  char retVal = 0;

  do {
    // здесь надо вызвать obj.makeMeFeelGood[1-3]
    retVal = obj.*callback // invalid use of non-static member function
  } while (retVal != 1);
};

void B::fun() {
    //вызвать wait и передать один из 3-х методов туда.
}

как сделать?

Компилю для AVR, со всеми вытекающими.



Последнее исправление: JackDaniel (всего исправлений: 2)

можно использовать подобие делегата из C# на С++, емнип авторство идеи сего - Александреску.

class Callback
{
private:
    struct X {};
    typedef void (X::*Func)();

    X *mTarget;
    Func mMethod;

public:
    Callback()
        : mTarget(0), mMethod(0)
    {
    }

    template <class Owner>
    Callback(Owner *owner, void (Owner::*func)())
        : mTarget(0), mMethod(0)
    {
            mMethod = reinterpret_cast<Func>(func);
            mTarget = reinterpret_cast<X *>(owner);
    }

    template <class Owner, class Arg>
    Callback(Owner *owner, void (Owner::*func)(Arg))
    {
            mMethod = reinterpret_cast<Func>(func);
            mTarget = reinterpret_cast<X *>(owner);
    }

    template <class Owner, class Arg1, class Arg2>
    Callback(Owner *owner, void (Owner::*func)(Arg1, Arg2))
    {
            mMethod = reinterpret_cast<Func>(func);
            mTarget = reinterpret_cast<X *>(owner);
    }

    bool CanCall()
    {
        return mMethod != 0;
    }

    bool operator ! ()
    {
        return (!mTarget || !mMethod);
    }

    bool operator == (const Callback &pCallback)
    {
        return (mTarget == pCallback.mTarget && mMethod == pCallback.mMethod);
    }

    bool operator != (const Callback &pCallback)
    {
        return !(*this == pCallback);
    }

    void Call()
    {
        if (mMethod)
        {
            if (mTarget) (mTarget->*mMethod)();
        }
    }

    void operator () ();

    template <class Arg>
            void operator() (Arg arg);

    template <class Arg1, class Arg2>
            void operator() (Arg1 arg1, Arg2 arg2);
};

inline void Callback::operator () ()
{
    if (mTarget && mMethod)
            (mTarget->*mMethod)();
}

template <class Arg>
void Callback::operator () (Arg arg)
{
    typedef void (X::*Mfn)(Arg);
    Mfn func = reinterpret_cast<Mfn>(mMethod);

    if (mTarget && func)
            (mTarget->*func)(arg);
}

template <class Arg1, class Arg2>
void Callback::operator () (Arg1 arg1, Arg2 arg2)
{
    typedef void (X::*Mfn)(Arg1, Arg2);
    Mfn func = reinterpret_cast<Mfn>(mMethod);

    if (mTarget && func)
            (mTarget->*func)(arg1, arg2);
}

AVR и C++. ну вот, не один я такой :) вообще будь очень осторожен, g++ для avr иногда генерит просто невероятную пургу, клонирует методы, конструкторы, а что он делает с virtual - это вообще неописуемо. Заглядывай в avr-objdump

dib2 ★★★★★
()
Ответ на: комментарий от JackDaniel

забить надо на указатель на функцию-член класса, ибо тягает с собой 2 поинтера. Я предпочитаю на шаблонах со static'ами выезжать.

dib2 ★★★★★
()
Ответ на: комментарий от dib2

>можно использовать подобие делегата из C# на С++, емнип авторство идеи сего - Александреску.

Идеи - хз, об этом ещё Гама писал. А реализация - да, похожа на Александресковский вариант Command.

yoghurt ★★★★★
()

Ну и зачем так издеваться над бедным кристальчиком? Осиль уже си

grouzen ★★
()

А сделать нормально, сделав waitCallback интерфейсом и реализующий его объект в конструктор, не судьба? Или вы только-только с дельфей и C-билдеров слезши?

no-dashi ★★★★★
()

как сделать?

///////////////////////////////////////////
class ICommand{
public:
    virtual void go() = 0;
}
///////////////////////////////////////////
class CommandA: ICommand{
public:
    virtual void go();
}

CommandA::go(){
   std::out << "Woof!";
}
///////////////////////////////////////////
class CommandB: ICommand{
public:
    virtual void go();
}

CommandB::go(){
   std::out << "Mioo...";
}
///////////////////////////////////////////

class Publisher{
public:
   void addListener(ICommand* com);

private:
   void runEvent();
   ICommand* com; 
}

Publisher::addListener(ICommand* com){
this->com = com;
}
Publisher::runEvent(){
this->com->go();
}

gandjubas
()
Ответ на: комментарий от anonymous

> Меня одного раздражает подобное говно?

Эстет, иди в толксы.

gandjubas
()

По-моему, тут просто пропущены скобки. Должно быть вроде так

retVal = (obj.*callback)();

И еще не уверен, что typedef внутри extern «C» для функции члена класса сработает правильно.

А вообще мне больше нравятся С-ые callback функции — проще они и мороки с вызовом меньше.

abalakin ★★
()
Ответ на: комментарий от no-dashi

AVR и C++ virtual в исполнении gcc - понятия почти не совместимые. Расходы - порядка 12 байт оперативы на каждую виртуальную функцию (это примерно). Тот же IAR толково хранит vtable в flashrom и жрет положенные 2 байта на функцию. В багзилле гцц вроде висело.

dib2 ★★★★★
()
Ответ на: комментарий от JackDaniel

> А легче никак?

А что тебе нужно?

Вот это:

// здесь надо вызвать obj.makeMeFeelGood[1-3]
retVal = obj.*callback // invalid use of non-static member function

Выглядит, как какая-то норкомания. Где тут коллбэк-то?

Что-то я думаю вообще забить на коллбэки с такой-то пургой.

Чё тут думать? Если можно забить, значит нужно забить.

LamerOk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.