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

时间:2008-10-19 18:05:21

标签: c++ class enums nested

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

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;

我可以看到嵌套私人枚举/课程的好处,但是当涉及到公共课程/课程时,办公室就分开了 - 它似乎更像是一种风格选择。

那么,您更喜欢哪种?为什么?

13 个答案:

答案 0 :(得分:44)

嵌套类

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

让我们想象下面的代码:

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

   // etc.
} ;

甚至:

class A
{
   public :
      class B ;

   // etc.
} ;

class A::B
{
   public :

   // etc.
} ;

所以:

  • Privilegied Access: A :: B拥有对A的所有成员(方法,变量,符号等)的特权访问权限,这会削弱封装
  • A的范围是符号查找的候选者:来自B内部的代码将看到来自A的所有符号作为符号查找的可能候选者,这可能会混淆代码
  • 前向声明:如果没有给出A的完整声明,就无法转发声明A :: B
  • 可扩展性:除非您是A
  • 的所有者,否则无法添加其他类A :: C.
  • 代码详细程度:将类放入类中只会使标题更大。你仍然可以将它分成多个声明,但是没有办法使用类似命名空间的别名,导入或使用。

作为结论,除非例外(例如嵌套类是嵌套类的一个私密部分......即使那时......),我认为普通代码中的嵌套类没有意义,因为缺陷超出了大小感知到的优势。

此外,在不使用C ++命名空间的情况下,它模仿命名空间是一种笨拙的尝试。

在专业方面,您将此代码隔离,如果是私有代码,则使其无法使用但是来自“外部”类......

嵌套枚举

优点:一切。

骗局:没什么。

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

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

// empty is from Value or Glass?

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

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定义了类枚举:

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

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

完全是针对这类问题。

答案 1 :(得分:6)

对于大型项目而言可能成为大问题的一个骗局是,无法对嵌套类或枚举进行前向声明。

答案 2 :(得分:2)

如果除了使用独立类的实现之外你永远不会使用依赖类,那么在我看来,嵌套类很好。

当你想要将“内部”类作为一个对象使用时,事情可能会开始变得有点怪异,你必须开始编写提取器/插入器例程。不是一个漂亮的情况。

答案 3 :(得分:2)

看起来您应该使用命名空间而不是类来以这种方式将彼此相关的事物分组。我在嵌套类中看到的一个骗局是你最终得到一个非常大的源文件,当你搜索一个部分时,这个文件可能很难理解。

答案 4 :(得分:2)

使用嵌套的公共C ++类没有任何利弊。只有事实。这些事实是由C ++标准强制执行的。关于嵌套公共C ++类的事实是pro还是con,取决于您尝试解决的特定问题。您给出的示例不允许判断嵌套类是否合适。

关于嵌套类的一个事实是,他们有权访问他们所属的类的所有成员。如果嵌套类不需要这样的访问,那么这是一个骗局。但是如果嵌套类不需要这样的访问,那么它不应该被声明为嵌套类。有些情况下,当一个类 A 想要授予某些其他类 B 的特权访问权限时。这个问题有三种解决方案

  1. B 成为 A
  2. 的朋友
  3. 使 B 成为 A
  4. 的嵌套类
  5. 制作 B 需要的方法和属性, A 的公共成员。
  6. 在这种情况下,#3违反了封装,因为 A 可以控制他的朋友和他的嵌套类,但不能控制调用他的公共方法或访问其公共属性的类。< / p>

    关于嵌套类的另一个事实是,除非您是的所有者,否则无法将另一个类 A :: C 添加为 A 的嵌套类A 的。但是,这是完全合理的,因为嵌套类具有特权访问权限。如果可以将 A :: C 添加为 A 的嵌套类,则 A :: C 可以欺骗 A < / em>授予对特权信息的访问权限;并且你违反了封装。它与friend声明基本相同:friend声明不授予您任何特殊权限,即您的朋友躲避其他人;它允许您的朋友访问您隐藏在非朋友中的信息。在C ++中,将某人称为朋友是一种无私的行为,而不是一种自私的行为。同样适用于允许类成为嵌套类。

    关于嵌套公共类的其他事实:

    • A的范围是B的符号查找的候选者:如果您不想这样做,请将 B 设为 A 的朋友,而不是嵌套类。但是,有些情况下您需要完全这种符号查找。
    • A :: B 无法正向声明 A A :: B 紧密耦合。能够在不知道 A 的情况下使用 A :: B 只会隐藏这一事实。

    总结一下:如果工具不符合您的需求,请不要责怪工具;责备自己使用该工具;其他人可能会有不同的问题,工具是完美的。

答案 5 :(得分:1)

paercebal说了关于嵌套枚举的所有内容。

WRT嵌套类,我常见且几乎唯一的用例是当我有一个操作特定类型资源的类时,我需要一个表示特定于该资源的数据类。在你的例子中,output_tray可能是一个很好的例子,但是如果类将要从包含类外部调用任何方法,或者主要是一个数据类,我通常不会使用嵌套类。我通常也不嵌套数据类,除非在包含的类之外没有直接引用包含的类。

因此,例如,如果我有一个printer_manipulator类,它可能有一个包含类的打印机操作错误,但打印机本身将是一个非包含类。

希望这会有所帮助。 :)

答案 6 :(得分:1)

请记住,您以后可以随时将嵌套类提升为顶级类,但如果不破坏现有代码,则可能无法执行相反的操作。因此,我的建议是首先将它作为嵌套类,如果它开始成为问题,请在下一个版本中将其作为顶级类。

答案 7 :(得分:0)

对我而言,将它放在外面的一个重要因素是它成为全局命名空间的一部分。如果枚举或相关类只适用于它所在的类,那么它是有道理的。因此,在打印机的情况下,包含打印机的所有内容都将知道对枚举PRINTER_TYPE的完全访问权限,它实际上并不需要知道它。我不能说我曾经使用过内部类,但是对于一个枚举来说,将它保持在内部似乎更合乎逻辑。正如另一张海报所指出的那样,使用命名空间对相似项进行分组也是一个好主意,因为堵塞全局命名空间确实是件坏事。我之前曾参与过大规模的项目,只需在全局命名空间上创建一个自动完成列表需要20分钟。在我看来,嵌套的枚举和命名空间的类/结构可能是最干净的方法。

答案 8 :(得分:0)

我赞同那些主张将你的枚举嵌入到课堂中的帖子,但有些情况下不这样做会更有意义(但请至少把它放在命名空间中)。如果多个类使用在不同类中定义的枚举,那么这些类直接依赖于其他具体类(拥有枚举)。这肯定代表了一个设计缺陷,因为该课程将负责该枚举以及其他职责。

所以,是的,如果其他代码只使用该枚举直接与该具体类接口,则将枚举嵌入到类中。否则,找一个更好的地方来保存枚举,例如命名空间。

答案 9 :(得分:0)

如果将枚举放入类或命名空间中,当您尝试记住枚举名称时,智能感知将能够为您提供指导。一件小事可以肯定,但有时小事情很重要。

答案 10 :(得分:0)

Visual Studio 2008似乎无法为嵌套类提供intellisense,所以在我过去常常使用嵌套类的大多数情况下,我已经切换到了PIMPL习惯用法。我总是将枚举放在类中,如果它只由该类使用,或者当多个类使用枚举时,在类的同一名称空间中的类之外。

答案 11 :(得分:0)

我可以看到嵌套类的con,可以更好地使用泛型编程。

如果小班级是在大班级之外定义的,你可以将大班级作为班级模板,并使用你将来可能需要的任何“小班级”班级。

通用编程是一个强大的工具,恕我直言,我们在开发可扩展程序时应该牢记这一点。奇怪的是,没有人提到这一点。

答案 12 :(得分:-1)

我遇到的嵌套类的唯一问题是C ++不允许我们在嵌套类函数中引用封闭类的对象。我们不能说“Enclosing :: this”

(但也许有办法?)