2010-04-30 3 views
2

Существует несколько дубликатов этого, но никто не объясняет, почему я могу использовать переменную-член для хранения указателя (в 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; 
} 
+0

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

ответ

7

При использовании указателя функции-члена вам необходимо указать объект, на котором он действует.

I.e. вам нужно создать указатель на экземпляр 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

Это пример БАР, который ему нужно создать, а не FOO. –

+1

@Billy ONeal: Скобки в '(foo -> * fptr) (a, b)' абсолютно необходимы. То, что вы сейчас просто не скомпилируете. – AnT

+0

Зачем нужно указывать объект? Разве разные объекты одного и того же класса имеют одинаковый адрес функции? – Jacob

2

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

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

+0

Спасибо, но я думал, что адрес функции-члена одинаковый для всех объектов --- или я ошибаюсь? – Jacob

+0

@Fyodor Soikin: +1 за исправление ошибки в моем ответе. –

+0

Да, он одинаковый для всех объектов. Поэтому вам не нужен объект для получения этого адреса. Но вам нужен объект для вызова функции по этому адресу. Функция-член нуждается в «этом» указателе - другими словами, ему нужен объект, по которому он вызван. –

1

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

Я не понимаю, где я использовал 'bar' вместо' BAR'? Спасибо за решение, но почему мне нужно использовать '-> *' с объектом класса? – Jacob

8

Видимо, вы поняли смысл 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 локальная переменная ,

+0

У меня создалось впечатление, что * все * объекты класса будут использовать функцию с тем же * адресом --- так зачем нам «указатель на объект», когда адрес функции не имеет ничего общего с объектом - - Или я ошибаюсь в этом? – Jacob

+0

@Jacob: Вы правы, что все функции используют один и тот же адрес, но если эта функция-член изменяет объект, он должен знать, какой экземпляр рассматриваемого класса необходимо изменить. Это достигается с помощью указателя 'this' и поэтому вам действительно нужен экземпляр класса, прежде чем вы сможете использовать указатель на функцию. –

+0

@AndreyT: +1 для исправления моего ответа :) –

0

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

Смежные вопросы