如何理解本声明中的类型

How to understand the typedef in this declaration

本文关键字:类型 声明 何理解      更新时间:2023-10-16

最近,我读了这本书有效的C ,并且在项目35中有关于Typedef的声明使我感到困惑。

class GameCharacter; // Question1: Why use forward declaration?
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter{
    public:
        typedef int (*HealthCalcFunc)(const GameCharacter&); // Question 2: What does this mean?
        explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
            : healthFunc(hcf)
        {}
        int healthValue() const
        {return healthFunc(*this); }
    private:
        HealthCalcFunc healthFunc;
};

所以我的第一个问题是:为什么作者在这里使用前向声明?有什么具体原因吗?

我的第二个问题是:我如何理解Typedef声明,以及如何使用它?我只知道typedef int MyInt;

所以我的第一个问题是,为什么作者在这里使用远期声明?

由于函数的声明defaultHealthCalc使用const GameCharacter&作为参数的类型,因此需要预先声明GameCharacter

我的第二个问题是如何理解Typedef声明

它声明了类型名称HealthCalcFunc,这是一种用于功能的指针,它将const GameCharacter&作为参数并返回int

以及如何使用它?

正如代码样本所示,

explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) // declare a parameter with type HealthCalcFunc; 
                                                               // the default argument is function pointer to defaultHealthCalc
: healthFunc(hcf)                                              // initialize healthFunc with hcf
{}
int healthValue() const
{return healthFunc(*this); }                                   // invoke the function pointed by healthFunc
HealthCalcFunc healthFunc;                                     // declare a member with type HealthCalcFunc 

由于使用 GameCharacterdefaultHealthCalc的正向声明,因此需要向前声明。如果没有远期声明,编译器将不知道以后会有一种名为 GameCharacter的类型,因此您需要转发声明,或在函数声明之前移动定义。

typedef的意思是命名int(*)(const GameCharacter&) HealthCalcFunc类型。这是int(const GameCharacter&)的功能指针。因此,Typedefs非常不可读,建议使用using声明:

using HealthCalcFunc = int(*)(const GameCharacter&);

所以我的第一个问题是,作者为什么在这里使用远期声明?

以便编译器知道遇到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));
}

另请参见我应该使用std ::函数或C 中的功能指针。

typedef int (*HealthCalcFunc)(const GameCharacter&);

在功能指针类型中声明名为HealthCalcFunctypedef,其中功能签名返回int并采用const GameCharacter&的参数。

需要向前声明,因为该类用作typedef中的参数类型。

不需要严格需要GameCharacter的正向声明;该功能声明可以读取:

int defaultHealthCalc(const class GameCharacter& gc);

具有与原始代码相同的效果。但是,将远期声明放在自己的行中被认为更可读。