【问题标题】:Should you declare enums inside or outside a class? [closed]你应该在类内还是类外声明枚举? [关闭]
【发布时间】:2012-03-09 08:05:47
【问题描述】:

如果枚举只在类成员函数中使用,你应该在类内部还是外部声明枚举?

namespace nspace
{

// need to append OC, as this pollutes the current namespace
enum OUTSIDE_CLASS {OC_POINTS, OC_LINES, OC_LINE_LOOP, :::};
enum OTHER_ENUM {OE_POINTS};
class VertexBuffer
{
public:
    enum INSIDE_CLASS {POINTS, LINES, LINE_LOOP, :::};
    void foo(OUTSIDE_CLASS e);
    void bar(INSIDE_CLASS e);
}
};

// usage
nspace::VertexBuffer v;
v.foo(nspae::VB_POINTS);
v.bar(nspace::VertexBuffer::POINTS); // more pedantic

【问题讨论】:

  • 与所有 [编码风格] 问题一样,答案是“视情况而定”。
  • 可能有人比我有更多的洞察力,但我的策略一直是在需要暴露之前不暴露。 (换句话说,如果它只是在内部使用,则保留在内部。)
  • 与编码风格问题一样,没有明确的答案。由于声明冲突的风险,污染全局范围通常不是一个好主意,但如果您保留在“自己的”命名空间内,这完全是一个偏好问题。
  • 我在私有部分的类内声明枚举(或其他任何东西),前提是类本身需要内部。在所有其他情况下,我更喜欢在外部定义它,尤其是在 C++11 中,因为如果你在类内部声明它,你将无法在 lambda 中使用它。
  • 您也许可以重构 replace the enum with a class hierarchy,例如状态或策略模式。

标签: c++ coding-style enums namespaces


【解决方案1】:

真正的目标是避免污染范围(全局或命名空间)并帮助将相关值分组在一起(在 IDE 中使用自动完成功能非常有用)。

使用 C++11,您可以使用以下方法声明强类型枚举:

enum class MyEnum {
  Value0,
  Value1
};

它们必须被调用为MyEnum::Value0(而不是Value0)。

在 C++03 中,您可以或多或少地模仿:

struct MyEnum {
  enum Type {
    Value0,
    Value1
  };
};

但是枚举的类型是MyEnum::Type,这是微妙的不同。

懒惰的选择是将它转储到一个类中,但我仍然喜欢嵌套一个作用域枚举,即使在一个类中,只是为了明确这些值不是松散的,而是相互关联

【讨论】:

  • -1 "这避免了污染全局范围。"不,它没有,但如果该声明必须在全局范围内(它很少必须这样做),那么污染将减少为单个名称(类型名称)而不是多个名称(枚举值)。跨度>
  • @Cheersandhth.-Alf:是的,从我的思路出发,真正的意图在介绍中表达了避免污染范围(全局或命名空间)。我会建议始终使用命名空间...希望脚本之类的程序(在 C++ 中,是的!)很少需要它。
【解决方案2】:

如果只有您的班级成员使用enum,最好在班级内声明enum
这可以防止命名空间/全局空间因不需要的符号名称而受到污染,而且还
对于类的用户来说更直观,它可以帮助用户知道enum只会被类使用。

您应该遵循的一般规则是:
不要在该范围内不会被访问(因此不需要)的范围(全局/命名空间)中添加任何符号。

【讨论】:

  • -1 全局命名空间不是类内声明的唯一替代方案。
  • @Cheersandhth.-Alf:答案并没有说全局命名空间是类声明的替代方案,它只是说明了为什么在这种情况下它不是一个好主意。我对你在这里投反对票感到有点困惑。
  • “这可以防止全局空间受到污染”如果不假设全局命名空间是唯一的选择就没有意义。
  • @Cheersandhth.-Alf:啊,好吧。修改以反映您提出的微妙观点。
  • 但是,OP 枚举声明是公开的,因此nspace::VertexBuffer::POINTS 可以访问它。您应该在您的答案中添加一条关于将其设为私有/受保护的注释。
【解决方案3】:

正如 Matthieu M. 提到的,在 C++11 中使用 Strongly typed enumerations

在 C++03 中模拟它们的一个好方法是将枚举包装在命名空间中。它比包装在 struct 中更好,因为该命名空间可能具有可以使用参数相关名称查找找到的函数。例如:

namespace MyEnum {
  enum Type {
    Value0,
    Value1
  };

  std::ostream& operator<<(std::ostream&, Type);
  std::istream& operator>>(std::istream&, Type&);
}

MyEnum::Type value;
std::cout << value; // uses the overload from MyEnum
std::cin >> value; // uses the overload from MyEnum

【讨论】:

  • -1 “更好因为”应该是“我更喜欢因为”。例如,我更喜欢包装在结构中,因为结构可以在类中进行类型定义(你不能在类中使用“使用命名空间”)。我现在写的方式还可以,但是如果我声称我的偏好比其他人的偏好“更好”,那么这将是一个毫无意义或不正确的主张。
  • 正如 Alf 所说,我更喜欢将结构用于 typedef 功能。将函数放在包含枚举的结构所在的命名空间中足以让 ADL 发挥作用。
  • @Alf: typedefusing namespace 做不同的事情,所以不清楚你为什么要比较它们,你可能想详细说明。我写了“更好”并解释了如何。
  • -1 将枚举包装在 namespace 中并不是更好,因为命名空间已为扩展开放。 IE。一些不相​​关的代码可能会执行namespace MyEnum { int Value0; },从而触发编译错误。
  • @FrerichRaabe 您可以像这样扩展任何命名空间,您的参数并不特定于命名空间中的枚举。
【解决方案4】:

这取决于。尽量减少实施细节的暴露。例如。将事物包含在命名空间和/或类和/或单独编译的实现文件中。正如希望非常清楚的那样,全局命名空间和类内绝对不是唯一的选择。即,在课堂上声明某些东西并不是减少曝光的唯一方法(那么还有其他方法吗?---哦,好吧,记住这个答案的第三句话)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-10
    • 1970-01-01
    • 2015-04-26
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多