Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Передать в класс указатель на функцию, если функция - член другого класса 
V
    Опции темы
marcusmae
Дата 5.10.2007, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: 5
Всего: 39



Всем привет.

Почитал похожие темы и мало-что понял, поэтому решил всё-таки спросить.

У меня есть класс, в который я должен передавать указатель на некую функцию-обработчик :

Код

// Defines field 2-dimensional variable.
template<typename T, class A> class GridVariable2d : public SparseMap2d<T> {

public :

    typedef T(A::*PtValueInitializer)(int ix, int iy);

private :

    // A pointer to the function, that initializes a 2d variable in the specified
    // grid point.
    T(*ptValueInitializer)(int ix, int iy);

public :

    // Get the storage value at the specified (ix, iy) position.
    virtual T get_Value(int ix, int iy) {
        T value = SparseMap2d<T>::get_Value(ix, iy);
        if (value == NULL)
            value = this->ptValueInitializer(ix, iy);
        return value;
    }

    // Initialize a new instance of the field 2-dimensional variable.
    GridVariable2d<T, A>(PtValueInitializer valueInitializer)
        : SparseMap2d<T>(NULL) {
        this->ptValueInitializer = ptValueInitializer;
    }
};


Шаблон T определяет тип данных, а с помощью шаблона класса A я стал выкручиваться из ошибки, связанной с тем, что передаваемый указатель на функцию (являющуюся членом другого класса) имеет соглашение __thiscall :

Код

// Defines the water characteristics structure.
struct Water {

private :

    const int M;

    // The water temperature distribution initializer.
    double* temperatureInitializer(int ix, int iy)
    { return Clonning::CopyArray<double>(this->initialTemperature, this->M + 1); }

public :

    const double Ts0, Sals0, Tb0, Salb0, row0;

    // The water temperature grid variable.
    GridVariable2d<double*,Water>* temperature;

    // Initialize a new instance of the water characteristics structure.    
    Water(double waterHashingLayerThickness, double lakeDepth, int M,
        double Ts0, double Sals0, double Tb0, double Salb0, double row0)
        : M(M), Ts0(Ts0), Sals0(Sals0), Tb0(Tb0), Salb0(Salb0), row0(row0)
    {
        // Create grid variables.
        this->temperature = new GridVariable2d<double*, Water>(
            &Water::temperatureInitializer);

        // Create the water temperature initial distributions
        // for the hashing layer levels.
        for (int index = 0; index < M + 1; index++)
            this->initialTemperature[index] = ...
    }
};


Правильно ли так действовать? = Или можно как-то обойтись без шаблона A?
Научите, пожалуйста, как это нормально делают.

Это сообщение отредактировал(а) marcusmae - 5.10.2007, 11:37


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
archimed7592
Дата 5.10.2007, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(marcusmae @  5.10.2007,  11:21 Найти цитируемый пост)
 T(*ptValueInitializer)(int ix, int iy);

А не проще ли написать
Код
PtValueInitializer ptValueInitializer;

smile

Цитата(marcusmae @  5.10.2007,  11:21 Найти цитируемый пост)
Или можно как-то обойтись без шаблона A?

Можно. См. boost::function.




--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
marcusmae
Дата 5.10.2007, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: 5
Всего: 39



[quote=archimed7592, 5.10.2007,  14:28, post1277470]
А не проще ли написать
Код

PtValueInitializer ptValueInitializer;

[quote]

Тогда на
Код

this->ptValueInitializer(ix,y)

говорит, что term does not evaluate to a function taking 2 arguments.


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
archimed7592
Дата 5.10.2007, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Слушай, оно у тебя вообще работает? smile

Цитата(marcusmae @  5.10.2007,  11:21 Найти цитируемый пост)
    GridVariable2d<T, A>(PtValueInitializer valueInitializer)
        : SparseMap2d<T>(NULL) {
        this->ptValueInitializer = ptValueInitializer;

Вот это, извини, малость бред(то же самое, что написать x = x;).


Цитата(marcusmae @  5.10.2007,  16:40 Найти цитируемый пост)
Тогда на

this->ptValueInitializer(ix,y)

говорит, что term does not evaluate to a function taking 2 arguments. 

Ну да, не заметил. А зачем тебе это поле? Оно же не способно хранить thiscall.

В общем вот тебе пример, додумай сам, что именно тебе нужно...
Код

template< class C, class R, class A1, class A2 >
void foo(C &obj, R (C:: *callback)(A1, A2), const A1 &a1, const A2 &a2)
{
    (obj .* callback)(a1, a2);
}

template< class C, class R, class A1, class A2 >
void bar(C *obj, R (C:: *callback)(A1, A2), const A1 &a1, const A2 &a2)
{
    (obj ->* callback)(a1, a2);
}

void foobar()
{
    SomeClass obj;
    SomeBase *pObj = new SomeDerived(/* ... */);
    foo(obj, &SomeClass::someMethod, 1, 2);

    SomeBase *pObj = new SomeDerived(/* ... */);
    foo(pObj, &SomeBase::someVirtualMethod, 3, 4); // вызовет SomeDerived::someVirtualMethod(если перекрыт)

    delete pObj;
}



--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
marcusmae
Дата 5.10.2007, 17:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: 5
Всего: 39



Цитата(archimed7592 @  5.10.2007,  17:08 Найти цитируемый пост)
Вот это, извини, малость бред(то же самое, что написать x = x;).

да-да, там должен стоять valueInitializer, и это не работает, тк проблему thiscall мне решить не удаётся  smile

В примере дайте, пожалуйста, хоть на код классов посмотреть...
Сам пытался вот по этим матерьялам научиться.

Блин, всего-то надо передать указатель на функцию-член другого класса, хранить его и запускать функцию по её указателю. Вот в C# бросил тип делегата в качестве аргумента, и всё работает. В плюсах же такое впечатление, что для этого надо лбом об стенку разбиться.  smile


Это сообщение отредактировал(а) marcusmae - 5.10.2007, 17:25


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
archimed7592
Дата 5.10.2007, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(marcusmae @  5.10.2007,  17:22 Найти цитируемый пост)
В примере дайте, пожалуйста, хоть на код классов посмотреть...

Код

#include <ostream>
#include <iostream>

class C
{
public:
    void foo(int a1, int a2)
    {
        std::cout << a1 << '\t' << a2;
    }
};

void test(C &obj, void (C:: *callback)(int, int), int a1, int a2)
{
    return (obj .* callback)(a1, a2);
}

int main()
{
    C c;
    test(c, &C::foo, 1, 2);
}





Цитата(marcusmae @  5.10.2007,  17:22 Найти цитируемый пост)
Вот в C# бросил тип делегата в качестве аргумента, и всё работает. В плюсах же такое впечатление, что для этого надо лбом об стенку разбиться.
Я же тебе ссылку даже на boost::function дал.
Код

class A
{
    boost::function< void(int, int) > callback;
public:
    explicit A(const boost::function< void(int, int) > &callback)
        : callback(callback)
    { }
    void test()
    {
        callback(1, 2);
    }
};

class B
{
public:
    void thiscallFoo(int a1, int a2)
    {
        std::cout << a1 << '\t' << a2;
    }
}

stdcallFoo(int a1, int a2)
{
    std::cout << a1 << '\t' << a2;
}

int main()
{
    B b;
    A a1(boost::bind(&B::thiscallFoo, boost::ref(b)));
    A a2(&stdcallFoo);
    a1.test();
    a2.test();
}



--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
marcusmae
Дата 7.10.2007, 23:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


Профиль
Группа: Участник
Сообщений: 874
Регистрация: 26.3.2006

Репутация: 5
Всего: 39



Вчера всё внимательно посмотрел и понял, что мне не хватает одного : ссылки на экземпляр класса, в котором живёт функция-обработчик, передаваемая по указателю. И ещё привелся к __cdecl :

Код

// Defines field 2-dimensional variable.
template<typename T, class A> class GridVariable2d : public SparseMap2d<T> {

public :

    typedef T(__cdecl A::*PtValueInitializer)(int ix, int iy);

private :

    // An instance of the template A class.
    A* obj;

    // A pointer to the function, that initializes a 2d variable in the specified
    // grid point.
   PtValueInitializer ptValueInitializer;

public :

    // Get the storage value at the specified (ix, iy) position.
    virtual T get_Value(int ix, int iy) {
        T value = SparseMap2d<T>::get_Value(ix, iy);
        if (value == NULL)
            value = ((*this->obj).*ptValueInitializer)(ix, iy);
        return value;
    }

    // Initialize a new instance of the field 2-dimensional variable.
    GridVariable2d<T, A>(A* obj, PtValueInitializer valueInitializer)
        : SparseMap2d<T>(NULL) {
        this->obj = obj;
        this->ptValueInitializer = valueInitializer;
    }
};


Соответственно, использующие сие классы стали свои функции тоже держать в __cdecl и передавать ссылку на себя в конструктор :

Код

// Defines the water characteristics structure.
struct Water {

private :

    const int M;

    // The water temperature distribution initializer.
    double* __cdecl temperatureInitializer(int ix, int iy)
    { return Clonning::CopyArray<double>(this->initialTemperature, this->M + 1); }

public :

    const double Ts0, Sals0, Tb0, Salb0, row0;

    // The water temperature grid variable.
    GridVariable2d<double*,Water>* temperature;

    // Initialize a new instance of the water characteristics structure.    
    Water(double waterHashingLayerThickness, double lakeDepth, int M,
        double Ts0, double Sals0, double Tb0, double Salb0, double row0)
        : M(M), Ts0(Ts0), Sals0(Sals0), Tb0(Tb0), Salb0(Salb0), row0(row0)
    {
        // Create grid variables.
        this->temperature = new GridVariable2d<double*, Water>(
            this, &Water::temperatureInitializer);

        // Create the water temperature initial distributions
        // for the hashing layer levels.
        for (int index = 0; index < M + 1; index++)
            this->initialTemperature[index] = ...
    }
};


И это работает. archimed7592, спасибо за Ваши примеры smile 


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0542 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.