Проблемы с указателем на методы - PullRequest
1 голос
/ 24 января 2012

Я только изучаю C ++, и у меня возникают трудности с указателями на методы. Скажем:

class One {
public:
int Add (int a, int b) {return a+b;}
};

typedef int (One::*pAdd) (int, int);

class Other {
public:
int Next (pAdd funct, int c){ return funct (c, 1);}

};

int main (){

One one;
Other other;

other.Next(one.Add, 2);

return 0;
}

У меня есть ряд проблем, о которых сообщил мой MinGW. Во-первых, я не вызываю funct правильно, так как компилятор настаивает на использовании. * Или -> *. Не знаю, как включить этот запрос, и любая помощь приветствуется. Теперь я мог бы решить свои проблемы, сделав методы статичными, чтобы использовать указатели в стиле c или передавать объекты и вызывать методы из Next, но я хочу понять указатели на методы. В основном, я озадачен, почему один. Добавить не является приемлемым входом. Метод для вызова однозначно определен (.Add) и соответствует моему typedef. Кроме того, я предоставляю экземпляр класса (one) из typedef, таким образом предоставляя контекст, в котором должен выполняться метод. Но вывод компилятора выглядит так, будто я не только пропустил синтаксис, но и пропустил концепцию. Итак, как передать указатель на метод с объектом в качестве контекста в качестве одного аргумента?

Ответы [ 4 ]

6 голосов
/ 24 января 2012

Основная проблема здесь заключается в том, что функции-члены не связаны с экземпляром объекта, они являются просто указателями на функции с немного отличающейся сигнатурой.

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

Я немного изменил пример кода:

#include <iostream>

class One {
public:
    int Add (int a, int b) {return a+b;}
};

typedef int (One::*pAdd) (int, int);

class Other {
public:
    int Next (One one, pAdd funct, int c){
        return (one.*funct)(c, 1);
    }
};

int main (){
    One one;
    Other other;

    std::cout << other.Next(one, &One::Add, 2) << std::endl;

    return 0;
}

И теперь работает . Возможно, его можно немного улучшить, но я думаю, что вы можете взять его отсюда.

Я рекомендую вам прочитать Указатели на функции-члены раздел c ++ faq lite , который очень хорошо объясняет это.

1 голос
/ 24 января 2012

Итак, как передать указатель на метод с объектом в качестве контекста в качестве одного аргумента?

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

class Other {
public:
    int Next (pAdd funct, One & o, int c){ return (o.*funct) (c, 1);}
}

int main (){
    One one;
    Other other;
    other.Next(&One::Add, one, 2);
}

Если вы хотите создать функциональный объект, который вызывает конкретную функцию-член определенного объекта, то одна из возможностей - использовать std::bind (или boost::bind, если вы еще не можете использовать C ++ 11):

#include <functional>

class Other {
public:
    int Next (std::function<int(int,int)> funct, int c){ return funct (c, 1);}
};

int main (){
    One one;
    Other other;

    using namespace std::placeholders;
    other.Next(std::bind(&One::Add, &one, _1, _2), 2);
}

или лямбда:

other.Next([&](int a, int b){return one.Add(a,b);}, 2);
0 голосов
/ 24 января 2012

У вас здесь куча проблем: one.Add является функцией-членом, и вы не можете просто вызвать ее.Вам также нужно иметь указатель на класс, чтобы вызывать его.Также вам нужно использовать специальные operator.* или operator->*.Вы также не можете взять адрес связанной функции-члена.

В общем, вы должны использовать шаблон и boost/std::bind, чтобы сделать все это терпимым или держаться подальше от него.

Вот модифицированный, рабочий код:

class One {
public:
  int Add (int a, int b) {return a+b;}
};

typedef int (One::*pAdd) (int, int);

class Other {
public:
  int Next (One* one, pAdd funct, int c){ return (one->*funct)(c, 1);}
};

int main (){

  One one;
  Other other;

  other.Next(&one, &One::Add, 2);

  return 0;
}
0 голосов
/ 24 января 2012

Указателям на членов нужен экземпляр для работы.По сути, это функции, которые принимают дополнительный параметр, который становится неявным указателем this.Чтобы вызвать функцию через указатель на член для текущего объекта, вы можете использовать такой код:

(this->*funct)(c, 1);

(вы будете обращаться к переменным-членам аналогично, но без вызова функции).

Объект, для которого вы вызываете член, не является частью указателя на член.В результате вам нужно получить что-то вроде этого:

&One::Add

Это становится более интересным, если функция-член перегружена: в этом случае вам нужно предоставить контекст, из которого можно определить перегрузку при полученииадрес.Я использую static_cast<>() для этого:

static_cast<int (One::*)(int,int)>(&One::Add)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...