在〈函式指標〉介紹過如何將函式指定給對應型態的函式指標,類別的成員函式也是函式,必要時也可以指向對應型態的指標。
要宣告成員函式的指標,與非成員函式的指標宣告類似,主要是要以 :: 來指定是哪個類別的成員函式,函式簽署必須符合,以〈定義類別〉的 Account 為例,可以如下宣告:
void (Account::*mf1)(double) = nullptr;
mf1 = &Account::deposit;
mf1 = &Account::withdraw;
string (Account::*mf2)() = &Account::to_string;
上例中 mf1 可以接受的是 Account 的 deposit 與 withdraw,而 mf2 可以接受的是 to_string,類別的實例會共用成員函式,呼叫成員函式時,必須將提供實例的位址給成員函式中的 this 指標,例如:
#include <iostream>
#include <string>
#include "account.h"
void call(Account &self, void (Account::*member)(double), double param) {
(self.*member)(param);
}
int main() {
Account acct = {"123-456-789", "Justin Lin", 1000};
call(acct, &Account::deposit, 1000);
call(acct, &Account::withdraw, 500);
cout << acct.to_string() << endl;
return 0;
}
如果 self 是個指標,就要透過 ->,例如:
#include <iostream>
#include "account.h"
void call(Account *self, void (Account::*member)(double), double param) {
(self->*member)(param);
}
int main() {
Account acct = {"123-456-789", "Justin Lin", 1000};
call(&acct, &Account::deposit, 1000);
call(&acct, &Account::withdraw, 500);
cout << acct.to_string() << endl;
return 0;
}
在 functional 標頭中定義有 mem_fn 函式,接受成員函式,傳回的呼叫物件,可以指定呼叫者收者,例如:
#include <iostream>
#include <functional>
#include "account.h"
void call(Account &self, void (Account::*member)(double), double param) {
mem_fn(member)(self, param);
}
int main() {
Account acct = {"123-456-789", "Justin Lin", 1000};
call(acct, &Account::deposit, 1000);
call(acct, &Account::withdraw, 500);
cout << acct.to_string() << endl;
return 0;
}
指定呼叫者時可以是個值,這相當於指定 *this 參考的對象,也可以是個指標,這就是指定 this:
#include <iostream>
#include <functional>
#include "account.h"
void call(Account *self, void (Account::*member)(double), double param) {
mem_fn(member)(self, param);
}
int main() {
Account acct = {"123-456-789", "Justin Lin", 1000};
call(&acct, &Account::deposit, 1000);
call(&acct, &Account::withdraw, 500);
cout << acct.to_string() << endl;
return 0;
}
也許你會想起〈高階函式〉中的 bind 函式,它也可以用來綁定 this,例如:
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
void call(Account &self, void (Account::*member)(double), double param) {
bind<void>(member, &self, _1)(param);
}
int main() {
Account acct = {"123-456-789", "Justin Lin", 1000};
call(acct, &Account::deposit, 1000);
call(acct, &Account::withdraw, 500);
cout << acct.to_string() << endl;
return 0;
}
為什麼要將 &self 當成是第一個參數呢?對於一個方法,例如 void Account::deposit(double amount),可以想像成編譯器將之轉換為 void Account::deposit(Account *this, double amount),而對於 acct.deposit(1000) 時,可以想像成編譯器將之轉換為 Account::deposit(&acct, 1000),實際上程式碼這麼寫不會編譯成功,因此才說是想像,然而可以透過 bind 來綁定第一個參數的值。
這就解答了另一個問題,怎麼使用 functional 的 function 模版來宣告成員函式型態呢?記得,第一個參數就是接受 this,因此就會是…
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
void call(Account &self, function<void(Account*, double)> member, double param) {
bind<void>(member, &self, _1)(param);
}
int main() {
Account acct = {"123-456-789", "Justin Lin", 1000};
call(acct, &Account::deposit, 1000);
call(acct, &Account::withdraw, 500);
cout << acct.to_string() << endl;
return 0;
}
那麼 static 成員函式呢?在〈static 成員〉中談過,static 成員屬於類別,某些程度上,就是將類別當成是一種名稱空間,實際上與一般函式無異,因此,函式指標的宣告與一般函式無異:
double (*fn)(double) = Math::toRadian;
類似類別的成員函式指標,也可以宣告類別的資料成員指標,例如:
#include <iostream>
using namespace std;
class Point {
public:
int x;
int y;
Point(int x, int y) : x(x), y(y) {}
};
void printCord(Point &pt, int Point::*cord) {
cout << pt.*cord << endl;
}
int main() {
Point pt(10, 20);
printCord(pt, &Point::x);
printCord(pt, &Point::y);
return 0;
}
在上例中,cord 是個資料成員指標,可以指向類別定義的資料成員,實際上要代表哪個實例的值域還需指定,同樣也可以透過 .*(參考的時候)、->*(指標的時候) 來使用。

