【问题标题】:How to understand the typedef in this declaration如何理解此声明中的 typedef
【发布时间】:2017-08-02 09:35:29
【问题描述】:

最近看了Effective 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;

【问题讨论】:

    标签: c++ typedef forward-declaration effective-c++


    【解决方案1】:

    GameCharacter 的前向声明不是严格需要的;函数声明可以是:

    int defaultHealthCalc(const class GameCharacter& gc);
    

    这与原始代码具有相同的效果。但是将前向声明放在单独的行中被认为更具可读性。

    【讨论】:

      【解决方案2】:

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

      因为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 
      

      【讨论】:

        【解决方案3】:

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

        以便编译器在遇到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&amp; 的函数。

        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++?

        【讨论】:

        • “因为代码仍然可以改进:在此处提及std::function 是合适的,但它是完全不同的选择,对于一个简单的例子,比如这个,当从轻量级函数指针类型切换到完全不同的,相比之下,std::function 的“重”生物时,提及改进可能会产生误导。两者都有自己的位置(大多数情况下,imo,std::function 应该是首选,但在使用较旧的 API 时......),但它们是非常不同的概念,是否使用一个而不是另一个应该根据上下文进行权衡。跨度>
        • @dfri:我认为std::function 比函数指针更容易编写、读取和应用,所以我认为它是标准解决方案,而函数指针是专用的野兽。
        • 是的,我同意,请注意我的忍者编辑。尽管如此,当提到std::function 作为一种始终改进时,指出在某些情况下更喜欢简单的函数指针(甚至是唯一的选择)可能是有价值的。无论如何,很好的答案,只是上面我的一个小署名!
        • @dfri:我添加了一个问题的链接,该问题检查了函数指针与 std::function 相比的优缺点。
        • @ChristianHackl 这个是最好的!非常感谢!
        【解决方案4】:

        由于defaultHealthCalc的前向声明使用GameCharacter,所以需要前向声明。如果没有前向声明,编译器不会知道后面会有一个名为GameCharacter的类型,所以你需要前向声明它,或者将定义移到函数声明之前。

        typedef 表示将类型命名为 int(*)(const GameCharacter&amp;) HealthCalcFunc。这是一个指向int(const GameCharacter&amp;) 的函数指针。出于这个原因,typedef 非常不可读,建议改用 using 声明:

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

        【讨论】:

          【解决方案5】:
          typedef int (*HealthCalcFunc)(const GameCharacter&);
          

          为函数指针类型声明一个名为 HealthCalcFunctypedef,其中函数签名返回 int 并采用 const GameCharacter&amp; 参数。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-07-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-06-19
            • 2011-09-17
            • 1970-01-01
            相关资源
            最近更新 更多