前置声明枚举类不起作用

21

在 State.h 文件中,我有以下内容:

enum class StateID : unsigned int;

在 State.cpp 文件中我有如下代码:

enum class StateID : unsigned int
{
    NullID = 0,
    MainMenuID,
    GamePlayID,
};

问题在于任何包含State.h的类都有前向声明,但我不能在任何cpp文件中使用除了定义它的States.cpp之外的任何enum值,比如StateID::MainMenuID。错误提示如下:

/home/lee/Projects/SuddenAwakening/Source/Game.cpp:24: error: 'MainMenuID' is not a member of 'StateID'

我正在运行LinuxMint15KDE,g++ 4.7,并且在其他部分使用c++11特性,例如nullptr、unique_ptr等,所以并不是我忘记了c++11的编译器标志。

1个回答

31
那是因为只有 States.cpp 知道在 enum class ID 中存在哪些成员。

包含 States.hpp 的文件只知道 enum class ID 是一个无符号整数的大小,仅此而已。

您需要在头文件中公开枚举值,以便任何需要知道枚举值(例如MainMenuID)的文件都可以使用它们。

您可以创建一个专门用于转发的头文件,例如StateFwd.hpp,然后将您的State.cpp重命名为State.hpp

您可能如何进行前向声明的示例

我已经在评论中的讨论后更新了我的答案。

fruit.hpp

任何选择包含此头文件的人都会知道哪些水果存在。

#ifndef FRUIT_HPP
#define FRUIT_HPP

enum class Fruit
{
    APPLE,
    ORANGE,
    BANANA
};

#endif

village.hpp

这个村庄里充满了因为对水果的渴望而驱使着他们的人。

#ifndef VILLAGE_HPP
#define VILLAGE_HPP

enum class Fruit;

namespace farmer
{
    bool is_fruit_for_sale(Fruit fruit);
    float get_cost_of_fruit(Fruit fruit);
}

namespace blind_but_greedy_merchant
{
    bool sell_fruit(Fruit fruit, float money);
}

namespace peasant
{
    inline bool buy_fruit(Fruit fruit, float money)
    {
        return blind_but_greedy_merchant::sell_fruit(fruit, money);
    }
}

#endif

farmer.cpp

这位农民只种植苹果和橙子,所以他从不出售香蕉。

#include "fruit.hpp"

namespace farmer
{
    bool is_fruit_for_sale(Fruit fruit)
    {
        switch ( fruit ) {
        case Fruit::APPLE:
        case Fruit::ORANGE:
            return true;
        case Fruit::BANANA:
            return false;
        }
        return false;
    }

    float get_cost_of_fruit(Fruit fruit)
    {
        switch ( fruit ) {
        case Fruit::APPLE:
            return 1.00f;
        case Fruit::ORANGE:
            return 2.50f;
        case Fruit::BANANA:
            return 200.0f;
        }
        return 0.0f;
    }
}

merchant.cpp

这个商人因为贪婪而变得盲目。他已经看不清自己在卖什么水果了。尽管如此,他仍然知道如何与农民打交道,将客户的请求转达给农民,并为所有水果添加高额利润。 这就是为什么fruit.hpp没有被包含进来的原因。

#include "village.hpp"

namespace blind_but_greedy_merchant
{
    bool sell_fruit(Fruit fruit, float money)
    {
        if ( !farmer::is_fruit_for_sale(fruit) ) {
            return false;
        }

        float inflatedcost = farmer::get_cost_of_fruit(fruit) * 3;

        if ( money < inflatedcost ) {
            return false;
        }

        return true;
    }
}

example.cpp

这将所有东西都串联在一起。在我们的例子中,我们想让农民去买一些水果。 我们知道我们想要什么样的水果; 香蕉。因此,我们需要包含fruit.hpp,否则我们就不能告诉农民为我们买香蕉。

在这种情况下,唯一知道存在什么样的水果的人只有我们(example.cpp)和农民(farmer.cpp)。 农民不需要知道水果的种类。这就像是我们给了他一张折叠好的纸条,上面写着我们想要的水果,但我们告诉他不要看。然后他只是把它递给了商贩,商贩看不懂纸条,于是就把它递给了农民。

#include "village.hpp"

#include "fruit.hpp"

int main()
{
    peasant::buy_fruit(Fruit::BANANA, 25.0f);

    return 0;
}

根据许多网站的说法,您可以按照我所做的方式进行前向声明。以下是其中一个链接:http://upto11blog.blogspot.com/2012/12/strong-enum-enum-class-strong-enum-enum.html - EddieV223
在链接的示例程序中,它展示了前向声明的目的。程序知道有一个名为Inventory::Fruit的东西,但它仍然不知道存在哪种水果。但是因为它知道有水果这个东西,所以它可以获取水果并获取它们的成本。 - Timma
如果没有访问Fruit的值,你会如何调用float getCost(Fruit leFruit)函数? - EddieV223
@EddieV223 在示例中他们确实这样做了。他们调用leInventory.getFruit();。这给我们一个Inventory::Fruit。我们不知道它是什么值,或者它可能是什么值。你能分配一个的唯一原因是因为编译器知道枚举类与int大小相同,你能做的唯一事情就是将一个Fruit值写入它或从它读取一个Fruit值。获取水果的唯一其他方法是构造一个(Fruit myfruit;)或通过静态转换一些值来分配它:Fruit myfruit = static_cast<Fruit>(100); - Timma
6
非常感谢夸奖!这个例子确实能够引起共鸣。“他再也看不清自己在卖什么水果了……所以才没包含fruit.hpp文件”- 真是太妙了。 - Chowlett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接