C++仿函数
仿函数(Functor)又叫函数对象(Function Object), 这是一个很有趣的编程能力,它来源于编程语言的操作符重载的特性,只要允许操作符重载的语言都可以实现仿函数的特性用法,比如c++,甚至一些本身并不包含函数特性的语言,例如java、c#。
我们知道C++允许很多操作符重载,其中就包含()即函数调用操作符,如果将一个类的()操作符进行重载,在类被示例化后在对象名称后加上()就会显得非常有趣,他就像一个函数一样被调用,被传递,甚至放在全局它看起来就像一个真的函数一样,这就是仿函数。
看下面的例子:
class loging {
public:
explicit CalculateSalary(const char* channel): channel_(channel) {
if (files_.find(channel) === files_.end()) {
throw std::exception("未配置日志文件");
}
file_ = files_[channel];
}
bool operator()(std::string source, std::string message) {
if (source_ != source) {
++step_;
}
... 记录日志
}
private:
const char* channel_;
int step_ = 0;
std::map<std::string, std::string> files_ = {
{"pay", "/var/run/logs/pay.log"},
{"async", "/var/run/logs/async.log"}
};
std::string file_;
std::string source_;
}
class step1 {
public:
void run(loging log) {
......
log("step1", "发生了错误1");
......
log("step1", "发生了错误2”);
}
}
class setp2 {
public:
void run(loging log) {
....
log("step2", “发生了错误3”);
...
log("step3", "发生了错误4");
}
}
int main(void) {
loging log;
step1 s1;
s1.run(log);
step2 s2;
s2.run(log);
}
首先实例化loging类, 然后传递了log对象, 在使用时使用了log("step2", “发生了错误3”);
, 和函数的调用方式非常相象。
如果采用函数指针作为参数传递,那我们看一下会发生什么情况,我们需要将step,files,file_,source_都做成全局的参数,这种情况下,你很难保证这些变量不被其他代码修改, 如果我们将从files_根据日志的channel选择日志存储的逻辑全部封装在函数内部,但很 明显这些都是可以复用的,封进函数会牺牲性能。而采用伪函数,则可以利用类的封装特性,而相比于类为函数显得更加简洁, 更加干净。
发表回复