Указатели на функции-члены - PullRequest
2 голосов
/ 30 апреля 2010

Существует несколько дубликатов этого, но никто не объясняет, почему я могу использовать переменную-член для хранения указателя (в FOO), но когда я пытаюсь сделать это с локальной переменной (в закомментированной части BAR), это незаконным. Кто-нибудь может объяснить это?

#include <iostream>
using namespace std;

class FOO
{
public:
 int (FOO::*fptr)(int a, int b);
 int add_stuff(int a, int b)
 {
  return a+b;
 }
 void call_adder(int a, int b)
 {  
  fptr = &FOO::add_stuff;
  cout<<(this->*fptr)(a,b)<<endl;
 }
};

class BAR
{
public:
 int add_stuff(int a, int b)
 {
  return a+b;
 }
 void call_adder(int a, int b)
 {  
  //int (BAR::*fptr)(int a, int b);
  //fptr = &BAR::add_stuff;
  //cout<<(*fptr)(a,b)<<endl;
 }
};

int main()
{
 FOO test;
 test.call_adder(10,20);
 return 0;
}

Ответы [ 5 ]

8 голосов
/ 30 апреля 2010

Очевидно, вы неправильно понимаете значение this->* в вызове в FOO.

Когда вы используете this->* с указателем члена fptr, часть this->* не имеет абсолютно никакого отношения к fptr, являющемуся членом FOO. Когда вы вызываете функцию-член, используя указатель на член, вы должны использовать оператор ->* (или оператор .*), и вам всегда необходимо указать фактический объект, который вы хотите использовать с этот указатель на член. Это то, что делает this->* часть вызывающего выражения. То есть вызов будет всегда выглядеть как

(<pointer-to-object> ->* <pointer-to-member>) (<arguments>)

или как

(<object> .* <pointer-to-member>) (<arguments>)

Левая сторона вызова (<pointer-to-object> или <object> выше) не может быть опущена.

Другими словами, не имеет значения, является ли fptr переменной-членом, локальной переменной, глобальной переменной или любой другой переменной, вызов через fptr будет всегда выглядеть как

(this->*fptr)(a, b);

при условии, что вы хотите вызвать его с *this объектом. Если в другом примере вы хотите вызвать его для какого-либо другого объекта, на который указывает указатель pfoo, вызов будет выглядеть следующим образом

FOO *pfoo;
...
(pfoo->*fptr)(a, b);

В вашем классе BAR вызов должен выглядеть как (this->*fptr)(a,b), хотя fptr является локальной переменной.

7 голосов
/ 30 апреля 2010

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

т.е. вам нужно создать указатель на экземпляр BAR (назовем его bar) и сделать:

(bar->*fptr)(a,b)

, чтобы вызвать функцию или экземпляр BAR и выполнить:

(bar.*fptr)(a,b)

Проще говоря:

#include <iostream>

class BAR
{
    int i;
public:
    BAR(): i(0) {};
    int AddOne() { return ++i; };
    int GetI() { return i; };
}

int main()
{
    BAR bar;
    auto fPtr = &BAR::AddOne; // This line is C++0x only (because of auto)
    std::cout << (bar.*fPtr)(); //This will print 1 to the console
    std::cout << std::endl;
    std::cout << bar.GetI(); //This will also print 1 to the console.
}
2 голосов
/ 30 апреля 2010

Я не думаю, что использование самой переменной является недопустимым. Недопустимо пытаться вызвать этот метод без экземпляра класса.

То есть вы должны действительно позвонить (someVar->*fptr)(a,b), где someVar имеет тип BAR*

1 голос
/ 30 апреля 2010

BAR::call_adder() было несколько проблем. Например, вы смешивали дело. В C ++ регистр имеет значение. BAR и bar - это не одно и то же. Во-вторых, вы исправили и правильно указали указатель после исправления проблем с регистром, но когда вы пытаетесь вызвать указатель на функцию-член, вам нужно использовать operator ->* с объектом класса. Вот это call_adder() исправлено

 void call_adder(int a, int b)
 {  
  int (BAR::*fptr)(int a, int b);
  fptr = &BAR::add_stuff;
  cout<<(this->*fptr)(a,b)<<endl;
 }
0 голосов
/ 30 апреля 2010

Когда вы вызываете функцию-член класса, компилятор генерирует код для установки 'this' во время выполнения функции. Когда вы вызываете его из указателя на функцию, это еще не сделано. Есть способы обойти это, но они не «гарантированно» работают и зависят от компилятора. Вы можете делать это, пока вы осторожны и знаете возможные проблемы, с которыми вы можете столкнуться.

...