在〈函数指针〉介绍过如何将函数指定给对应类型的函数指针,类的成员函数也是函数,必要时也可以指向对应类型的指针。
要定义成员函数的指针,与非成员函数的指针定义类似,主要是要以::
来指定是哪个类的成员函数,函数签署必须符合,以〈定义类〉的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
是个数据成员指针,可以指向类定义的数据成员,实际上要代表哪个实例的值域还需指定,同样也可以透过.*
(参考的时候)、->*
(指针的时候) 来使用。