Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Как передать метод объекта в функцию?


Автор: tararataka 9.9.2010, 11:13
Ну и собственно, как?  smile  Я разобрался как передавать функции и объекты. А метод объекта в функцию не влазит.  smile 

Автор: djamshud 9.9.2010, 11:22
Код

void foo(void(Class::*ptr)(int,double));


Как-то так.

Автор: azesmcar 9.9.2010, 11:23
Код

class X
{
public:
    void foo()
    {
        std::cout << "X::foo()" << std::endl;
    }
};

typedef void (X::*method)();

void call(X* ptr, method xm)
{
    (ptr->*xm)();
}

int main() 
{
    X x;
    method m = &X::foo;
    call(&x, m);
}

речь об этом?

Автор: tararataka 9.9.2010, 13:09
djamshud azesmcar
Ага, спасибо, это оно самое.

То есть мне нужно передать и адрес на объект и на метод класса, а потом "соединить" их.

А я могу делать это как-то более универсально, ну что-бы проделывать это с объектами разных классов? Или это единственный путь?

Автор: mrbrooks 9.9.2010, 13:18
tararataka, здесь на мой взгляд самый http://www.parashift.com/c++-faq-lite/pointers-to-members.html. 

Автор: azesmcar 9.9.2010, 13:22
Цитата(tararataka @  9.9.2010,  13:09 Найти цитируемый пост)
А я могу делать это как-то более универсально, ну что-бы проделывать это с объектами разных классов? Или это единственный путь? 

можно подробнее?

Автор: djamshud 9.9.2010, 13:26
tararataka, указатель на член класса А не получится использовать с объектом класса В, если только они не находятся в родственных связях. Если вы об этом.

Автор: tararataka 9.9.2010, 14:47
Кстати. Вот ещё подробный туториал. Я по нему разбираюсь.
http://www.newty.de/fpt/index.html

azesmcar
Цитата
можно подробнее?

Эээээ. Ну для сумрачного плана.

djamshud
Цитата
указатель на член класса А не получится использовать с объектом класса В, если только они не находятся в родственных связях. Если вы об этом.

Тогда шаблоны?

Автор: tararataka 9.9.2010, 16:45
Так вот шаблон.
Код

template<typename TO> // TO - Type Object
void tdeleg(TO *pt2Object, void (TO::*p2method)()) {
    (pt2Object->*p2method)();
}


Он позволяет этой функции работать с любыми классами.
Код

tdeleg(&any,&Any::tails);

Но всё равно это неудобно. Нужно давать адрес объекта, затем ещё адрес функции класса. Нельзя это как-нибудь тоже оптимизировать? Что бы я указал только метод any.tails , а препроцессор бы превратил это в нужное выражение?

Автор: Леопольд 9.9.2010, 20:17
tararataka, если метод не статический, то ему в аргументах передаётся указатель на интанс класса, который известен под именем this.

Автор: Cheloveck 9.9.2010, 21:03
А ведь об этом написано почти во всех книгах. Вы пробовали почитать?
http://xmages.net/show.php/1784139_out-png.html

Автор: tararataka 10.9.2010, 09:06
Леопольд
Цитата

tararataka, если метод не статический, то ему в аргументах передаётся указатель на интанс класса, который известен под именем this. 

 smile 

С использованием этого указателя можно переписать шаблон так, что бы передавать внутрь только что то вроде &any.tails ? 

Код

template<typename TO> // TO - Type Object
void tdeleg(TO *pt2Object, void (TO::*p2method)()) {
    (pt2Object->*p2method)();
}

Автор: Cheloveck 10.9.2010, 09:17
tararataka, у каждого объекта класса свой набор данных. Статические методы принадлежат классу, а не объекту. Таким образом из статического метода нельзя работать с не статическими данными объекта (собственно объекта не будет). ТО, что вы хотите - невозможно, в принципе. Ещё раз настоятельно рекомендую прочитать учебник по C++. Там всё написано.

Автор: tararataka 10.9.2010, 09:35
Цитата

ТО, что вы хотите - невозможно, в принципе.

Это снимает вопрос. Но вот в куте же это реализовано. Или это они там через свой moc нашаманили?  smile 

Cheloveck
Цитата
Ещё раз настоятельно рекомендую прочитать учебник по C++.

Ну ты бы название что-ли сказал. А ту книжку что я читал, так там про эти Function Pointers, Callbacks and Functors ничего нет. Ну кроме упоминания предикатов в в стл.

Автор: Cheloveck 10.9.2010, 10:01
Цитата(tararataka @  10.9.2010,  09:35 Найти цитируемый пост)
там через свой moc нашаманили?

Да, в куте не совсем C++.


Цитата(tararataka @  10.9.2010,  09:35 Найти цитируемый пост)
Ну ты бы название что-ли сказал.

Бьерн Страуструп - Язык программирования C++

Автор: djamshud 10.9.2010, 10:41
tararataka, что именно вы хотите скопировать из куте? Я не совсем понимаю. Покажите пример использования. Ибо moc отвечает только за обработку signals: и slots:, все остальное - обычный С++.

Автор: tararataka 10.9.2010, 11:14
djamshud 
Собственно я это и имел ввиду. Cвязывание двух функций. smile

Собственно на рсдн есть пример реализации, во всяком случае похожей идеи. Но оно выглядит так, что на это смотреть страшно.

Автор: djamshud 10.9.2010, 11:23
tararataka, что - это? сама функция connect moc-ом не обрабатывается. Точнее, это макрос.

Добавлено через 1 минуту и 6 секунд
То есть вы хотите сделть свои сигналы/слоты, правильно? То есть систему посыла сообщений в программе, да?

Автор: xvr 10.9.2010, 11:59
Цитата(tararataka @  9.9.2010,  13:09 Найти цитируемый пост)
А я могу делать это как-то более универсально,

Насколько я понимаю вам нужен __closure указатель. С++ напрямую не поддерживает. Поддерживается как расширение языка в Borland C++ Builder (или как оно сейчас называется)
Не уверен, что его можно вообще реализовать в С++ с ТЕМ ЖЕ синтаксисом, что и в BCB

Автор: tararataka 10.9.2010, 12:45
djamshud
Код
То есть вы хотите сделть свои сигналы/слоты, правильно? То есть систему посыла сообщений в программе, да?

Ага. Только я так понимаю лучше этим не заморачиваться. )

Автор: djamshud 10.9.2010, 12:58
tararataka, ну почему. Я ради интереса делал это когда-то. На самом деле все очень просто. Но можно взять иготовые из Qt, boost или еще какой-нибудь библиотеки. Если на выходных в инет вылезу, выложу свою реализацию. Или в понеделник.

Автор: tararataka 10.9.2010, 14:01
djamshud
Цитата
Если на выходных в инет вылезу, выложу свою реализацию. Или в понеделник.

Давай, интересно будет посмотреть.

Автор: Master01 10.9.2010, 21:27


посмотрите boost::bind

а вдруг это то что вы искали

Автор: djamshud 13.9.2010, 20:37
Во. Версия сырая и требует обработки напи^Wмакросами. Очень легко приделать регистрацию не только методов, но и обычных функций. Также может захотеться передавать что-нибудь через сигналы (в данной версии они умеют только пинать соседей). Самый простой способ - использовать какую-нибудь абстрактную структуру или набор variant-ов. Полноценно передача параметров делается через огромные костыли с помощью шаблонов (см реализацию сигналов в boost) или с помощью препроцесора (см Qt).

Код

#include<stdint.h>
#include<string.h>
#include<stdio.h>

#include<vector>

// #include<stLogger.h>
#define stDebug(...) fprintf(stderr,"%s: ",__PRETTY_FUNCTION__); fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n")


class signaler {
protected:
    class caller_iface;
    template<typename T>class caller;
    struct sig_t;
    typedef uint8_t member_t[sizeof(void*)*8];//buf for member pointer. buf is so large for stupid compilers like MSVC
    typedef std::vector<caller_iface*> dst_t;

    std::vector<sig_t> sigs;

    template<typename T>
    dst_t* __findSignal(void(T::*)());

public:

    template<typename T>
    void __registerSignal(void(T::*)());

    template<typename Tsrc,typename Tdst>
    void __addSlot(void(Tsrc::*)(),Tdst*,void(Tdst::*)());

    template<typename T>
    void __emit(void(T::*)());

};

struct signaler::sig_t {
    member_t fnc;
    dst_t dst;
};

class signaler::caller_iface {
public:
// virtual bool compare(caller_iface*)=0; //I'll need it when I want remove slots (aka disconnect)
    virtual void call()=0;
};


template<typename T>
class signaler::caller:public signaler::caller_iface {
protected:
    T *obj;
    void(T::*fnc)();
public:
    caller(T*,void(T::*)());
    void call();
};

template<typename T>
signaler::caller<T>::caller(T *_obj,void(T::*_fnc)()):obj(_obj),fnc(_fnc) {
}

template<typename T>
void signaler::caller<T>::call() {
    (this->obj->*this->fnc)();
}


template<typename T>
signaler::dst_t* signaler::__findSignal(void(T::*fnc)()) {
    for (int i=0;i<this->sigs.size();i++)
        if (memcmp(&fnc,this->sigs[i].fnc,sizeof(fnc))==0)
            return &this->sigs[i].dst;
    return 0;
}

template<typename T>
void signaler::__registerSignal(void(T::*fnc)()) {
    if (this->__findSignal(fnc)!=0) {
        stDebug("signal is already registred.");
        return;
    }
    struct sig_t sig;
    memset(sig.fnc,0,sizeof(sig,fnc));
    memcpy(sig.fnc,&fnc,sizeof(fnc));
    this->sigs.push_back(sig);
}

template<typename Tsrc,typename Tdst>
void signaler::__addSlot(void(Tsrc::*s_fnc)(),Tdst *d_obj,void(Tdst::*d_fnc)()) {
    dst_t *vct=this->__findSignal(s_fnc);
    if (vct==0) {
        stDebug("can not find signal.");
        return;
    }
    vct->push_back(new caller<Tdst>(d_obj,d_fnc));
}

template<typename T>
void signaler::__emit(void(T::*fnc)()) {
    dst_t *vct=this->__findSignal(fnc);
    if (vct==0) {
        stDebug("can not find signal.");
        return;
    }
    for (int i=0;i<vct->size();i++)
        vct->at(i)->call();
}





class test1:public signaler {
public:
    void sig1() {}
    void sig2() {}
};

class test2 {
public:
    char const *str;
    test2(char const *str) {
        this->str=str;
    }
    void slot1() {
        stDebug("%s",str);
    }
};


int main() {
    test1 t1;

    test2 t21("Hello");
    test2 t22("world");

    t1.__registerSignal(&test1::sig1);
    t1.__addSlot(&test1::sig1,&t21,&test2::slot1);
    t1.__addSlot(&test1::sig1,&t22,&test2::slot1);


    t1.__emit(&test1::sig1);

    return 0;
}


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)