Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: передача метода в качестве параметра  (Прочитано 8822 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« : 15-07-2004 19:03 » 

Имеем класс, работающий с двумерным массивом объектов. У класса есть ряд методов типа bool (*)(const int x, const int y), которые возвращают всякие флаги относительно состояний объектов массива. Хочу написать метод, в котором перебираются области массива заданной формы, но универсальный. Для этого хотел в качестве параметра последнего метода передать указатель на метод вышеуказанного типа, однако GCC этого делать не даёт, указывает на несоответствие типов. В коде попытка моего решения выглядит примерно так

Код:
typedef bool (*checker)(const int x, const int y);

class field
{
    ...
public:
    ...
    bool somecheck1(const int x, const int y);
    bool somecheck2(const int x, const int y);
    ...
    int calcaround(const int x, const int y, checker cf);
    ...
    void somefunc();
}
...
int field::calcaround(const int x, const int y, checker cf)
{
    ...
    bool res = cf(x, y);
    ...
}
...
void field::somefunc()
{
    ...
    int z1 = this->calcaround(x, y, this->somecheck1);
    int z2 = this->calcaround(x, y, this->somecheck2);
    ...
}

Компилятор упирает на несоответствие типов. Т.е. тип checker не совпадает с типом методов класса. Явное преобразование (checker)this->somecheck1 также вызывает ошибку. Мне кажется, что методу класса на стадии компиляции добавляются всякие параметры вроде того же this, явно в коде не указанные.

Как разрешается подобный случай?

Страуструп у меня старый, второй редакции - там подобный случай не рассмотрен. Там предлагается либо объекты передавать в качестве параметра, либо использовать обычные функции (не методы класса). Один раз я с подобной ситуацией сталкивался, и вышел из неё, использовав friend функции, но это некрасиво. Порождать кучу классов, не несущих никакого смысла, чтобы не передавать указатель на метод - это загромождает код. Создать некий enum, а в универсальном методе по switch выбирать нужный метод - терпимо, но черевато переписыванием универсального метода при каждом изменении числа методов проверки объекта - не хотелось бы.

Кто что скажет?
« Последнее редактирование: 30-11-2007 20:24 от Алексей1153++ » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Xeysan
Гость
« Ответ #1 : 15-07-2004 20:58 » 

Вместо
Код:
typedef bool (*checker)(const int x, const int y);
..используй
Код:
class field;
typedef bool ( field::*checker)( const int x, const int y );

Вызывать так:
Код:
int field::calcaround(const int x, const int y, checker cf)
{
    ...
    bool res = (this->*cf)(x, y);
    ...
}

Ошибка в том, что методам класса неявно передается указатель на объект класса. После явного преобразования ты заставляешь его использовать мусор.

А вообще более общее решение - это использование паттерна Command ( GoF ). Не конкретно к твоему случаю, а так про функторы в общем.
« Последнее редактирование: 30-11-2007 20:26 от Алексей1153++ » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 15-07-2004 21:58 » 

я так пробовал уже...
но дело в передаче метода, т.е.
Код:
int z1 = this->calcaround(x, y, this->somecheck1);
получается ошибка
Код:
mc.cpp:116: no matching function for call to `field::calcaround(const int&, const int&, <unknown type>)'
mc.cpp:66: candidates are: int field::calcaround(int, int, bool (field::*)(int, int))
а когда задаёшь явное преобразование
Код:
int z1 = this->calcaround(x, y, (checker)this->somecheck1);
то компилятору опять не нравится
Код:
mc.cpp:116: assuming pointer to member `bool field::somecheck1(int, int)'
mc.cpp:116: (a pointer to member can only be formed with `&field::somecheck1(int, int)'
я думаю: ладно, раз ему надо через & адрес брать, то пусть. Пишу
Код:
int z1 = this->calcaround(x, y, (checker)&this->somecheck1);
хотя с точки зрения C это неправильно, т.к. имя функции без последующих скобок рассматривается как указатель (адрес начала функции), и в данном случае я получаю указатель на указатель.
Компилятор же на последнее заявляет
Код:
mc.cpp:116: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say `&field::somecheck1'

чего-то я, видимо, не понимаю...
« Последнее редактирование: 30-11-2007 20:28 от Алексей1153++ » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 16-07-2004 07:16 » 

всё Улыбаюсь по утру разобрался.

надо
Код:
int z1 = this->calcaround(x, y, &field::somecheck1);

Метод - функция. Её адрес известен на стадии компиляции, поэтому можно класс использовать, а не объект класса. Единственно, что будет скверно, это передача виртуального метода какого-либо класса. Его-то адрес как раз в runtime определяется. Но пока такой проблемы не стоит.

И, кстати, просьба модератору перенести эту тему в соседний раздел... Тут всё ж не ОС, а сам язык. А пригодиться кому-нибудь может.
« Последнее редактирование: 30-11-2007 20:29 от Алексей1153++ » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines