所以我的第一个问题是为什么作者在这里使用前向声明?
以便编译器在遇到int defaultHealthCalc(const GameCharacter& gc); 行时知道GameCharacter 是一个有效名称。
而我的第二个问题是如何理解typedef声明以及如何使用它?
理想情况下,您不再使用它。
从 C++11 开始,using 是更好的选择,因为它更具可读性;与typedef'ed 函数指针不同,它清楚地将名称与名称所描述的分开。比较一下:
typedef int (*HealthCalcFunc)(const GameCharacter&);
有了这个:
using HealthCalcFunc = int (*)(const GameCharacter&);
在typedef 版本中,名称HealthCalcFunc 的两侧被名称所描述的内容包围。这会损害可读性。
但是代码仍然可以改进,因为 C++11 还引入了std::function 作为函数指针上方的替代和/或抽象层。
using HealthCalcFunc = std::function<int(const GameCharacter&)>;
这太可读了,几乎不需要解释。 HealthCalcFunc 是一个返回 int 并接受 const GameCharacter& 的函数。
defaultHealthCalc 函数符合此定义。这是一个完整的例子:
#include <functional>
class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter {
public:
using HealthCalcFunc = std::function<int(const GameCharacter&)>;
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: healthFunc(hcf)
{}
int healthValue() const
{return healthFunc(*this); }
private:
HealthCalcFunc healthFunc;
};
std::function 的优点在于您不受限于独立功能。你可以传递每一个类似函数的东西。以下是一些示例:
struct Functor
{
int f(const GameCharacter& gc);
};
int main()
{
// normal function:
GameCharacter character1(defaultHealthCalc);
// lambda:
GameCharacter character2([](auto const& gc) { return 123; });
// using std::bind:
Functor functor;
using namespace std::placeholders;
GameCharacter character3(std::bind(&Functor::f, functor, _1));
}
另见Should I use std::function or a function pointer in C++?。