如何理解此声明中的typedef

Lix*_*Bai 4 c++ typedef forward-declaration effective-c++

最近,我读了有效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;
};
Run Code Online (Sandbox Code Playgroud)

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

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

son*_*yao 13

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

由于函数的声明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 
Run Code Online (Sandbox Code Playgroud)


Rak*_*111 11

由于使用了前向声明defaultHealthCalc,因此需要前进声明GameCharacter.如果没有前向声明,编译器将不会知道稍后会有一个名为的类型GameCharacter,因此您需要转发声明它,或者在函数声明之前移动定义.

typedef意味着要命名类型int(*)(const GameCharacter&) HealthCalcFunc.这是一个指向a的函数指针int(const GameCharacter&).因此,typedef非常难以理解,建议使用using声明:

using HealthCalcFunc = int(*)(const GameCharacter&);
Run Code Online (Sandbox Code Playgroud)


πάν*_*ῥεῖ 9

typedef int (*HealthCalcFunc)(const GameCharacter&);
Run Code Online (Sandbox Code Playgroud)

声明一个函数指针类型的typedef命名HealthCalcFunc,其中函数签名返回a int并获取参数const GameCharacter&.

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


Chr*_*ckl 8

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

这样编译器就知道GameCharacterint defaultHealthCalc(const GameCharacter& gc);遇到该行时它是一个有效的名称.

我的第二个问题是如何理解typedef声明以及如何使用它?

理想情况下,您不再使用它.

从C++ 11开始,它using是一个更好的选择,因为它更具可读性; 与typedef'ed函数指针不同,它清楚地将名称与名称描述的名称分开.比较一下:

typedef int (*HealthCalcFunc)(const GameCharacter&);
Run Code Online (Sandbox Code Playgroud)

有了这个:

using HealthCalcFunc = int (*)(const GameCharacter&);
Run Code Online (Sandbox Code Playgroud)

在该typedef版本中,名称HealthCalcFunc由名称描述的名称左右包围.这会伤害可读性.


但代码仍然可以改进,因为C++ 11也std::function作为函数指针之上的替代和/或抽象层引入.

using HealthCalcFunc = std::function<int(const GameCharacter&)>;
Run Code Online (Sandbox Code Playgroud)

这是如此可读,几乎没有必要解释.HealthCalcFunc是一个返回int并取a 的函数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;
};
Run Code Online (Sandbox Code Playgroud)

最棒的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));
}
Run Code Online (Sandbox Code Playgroud)

另请参阅我应该在C++中使用std :: function还是函数指针?.