使用嵌套 C++ 类和枚举的优缺点?

2021-12-09 00:00:00 class nested enums c++

使用嵌套的公共 C++ 类和枚举的优缺点是什么?例如,假设您有一个名为 printer 的类,并且该类还存储有关输出托盘的信息,您可以:

What are the pros and cons of using nested public C++ classes and enumerations? For example, suppose you have a class called printer, and this class also stores information on output trays, you could have:

class printer
{
public:
    std::string name_;

    enum TYPE
    {
        TYPE_LOCAL,
        TYPE_NETWORK,
    };

    class output_tray
    {
        ...
    };
    ...
};

printer prn;
printer::TYPE type;
printer::output_tray tray;

或者:

class printer
{
public:
    std::string name_;
    ...
};

enum PRINTER_TYPE
{
    PRINTER_TYPE_LOCAL,
    PRINTER_TYPE_NETWORK,
};

class output_tray
{
    ...
};

printer prn;
PRINTER_TYPE type;
output_tray tray;

我可以看到嵌套私有枚举/类的好处,但是当涉及到公共枚举/类时,办公室是分开的 - 这似乎更像是一种风格选择.

I can see the benefits of nesting private enums/classes, but when it comes to public ones, the office is split - it seems to be more of a style choice.

那么,你更喜欢哪个,为什么?

So, which do you prefer and why?

推荐答案

嵌套类

嵌套在类中的类有几个副作用,我通常认为这些是缺陷(如果不是纯粹的反模式).

Nested classes

There are several side effects to classes nested inside classes that I usually consider flaws (if not pure antipatterns).

让我们想象以下代码:

class A
{
   public :
      class B { /* etc. */ } ;

   // etc.
} ;

甚至:

class A
{
   public :
      class B ;

   // etc.
} ;

class A::B
{
   public :

   // etc.
} ;

所以:

  • 特权访问: A::B 对 A 的所有成员(方法、变量、符号等)具有特权访问权限,这削弱了封装性
  • A 的范围是符号查找的候选: 来自 B 内部的代码将看到来自 A 的 所有 符号作为符号查找的可能候选,这可能会混淆代码莉>
  • forward-declaration: 没有完整的 A 声明就无法前向声明 A::B
  • 可扩展性:除非您是 A 的所有者,否则不可能添加另一个类 A::C
  • 代码冗长: 将类放入类只会使标头变大.您仍然可以将其分成多个声明,但无法使用类似名称空间的别名、导入或使用.
  • Privilegied Access: A::B has privilegied access to all members of A (methods, variables, symbols, etc.), which weakens encapsulation
  • A's scope is candidate for symbol lookup: code from inside B will see all symbols from A as possible candidates for a symbol lookup, which can confuse the code
  • forward-declaration: There is no way to forward-declare A::B without giving a full declaration of A
  • Extensibility: It is impossible to add another class A::C unless you are owner of A
  • Code verbosity: putting classes into classes only makes headers larger. You can still separate this into multiple declarations, but there's no way to use namespace-like aliases, imports or usings.

作为结论,除非有异常(例如嵌套类是嵌套类的一个亲密部分......即使如此......),我认为在普通代码中嵌套类没有意义,因为缺陷的重要性超过了数量级感知到的优势.

As a conclusion, unless exceptions (e.g. the nested class is an intimate part of the nesting class... And even then...), I see no point in nested classes in normal code, as the flaws outweights by magnitudes the perceived advantages.

此外,它闻起来像是在不使用 C++ 命名空间的情况下模拟命名空间的笨拙尝试.

Furthermore, it smells as a clumsy attempt to simulate namespacing without using C++ namespaces.

在专业方面,您隔离此代码,如果是私有的,则使其无法使用但从外部"隔离类...

On the pro-side, you isolate this code, and if private, make it unusable but from the "outside" class...

优点:一切.

缺点:没什么.

事实是枚举项会污染全局范围:

The fact is enum items will pollute the global scope:

// collision
enum Value { empty = 7, undefined, defined } ;
enum Glass { empty = 42, half, full } ;

// empty is from Value or Glass?

通过将每个枚举放在不同的命名空间/类中可以避免这种冲突:

Ony by putting each enum in a different namespace/class will enable you to avoid this collision:

namespace Value { enum type { empty = 7, undefined, defined } ; }
namespace Glass { enum type { empty = 42, half, full } ; }

// Value::type e = Value::empty ;
// Glass::type f = Glass::empty ;

注意 C++0x 定义了类枚举:

Note that C++0x defined the class enum:

enum class Value { empty, undefined, defined } ;
enum class Glass { empty, half, full } ;

// Value e = Value::empty ;
// Glass f = Glass::empty ;

正是针对这类问题.

相关文章