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

使用嵌套的公共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; 

我可以看到嵌套私有枚举/类的好处,但是当涉及到公共的时候,办公室是分裂的 – 似乎更像是一种风格select。

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

嵌套的类

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

我们来想象下面的代码:

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

甚至:

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

所以:

  • 特权访问: A :: B特权访问A(方法,variables,符号等)的所有成员,这削弱了封装
  • A的作用域是符号查找的候选对象:来自B内部的代码会将来自A的所有符号视为符号查找的可能候选对象,这可能会混淆代码
  • 前向声明:没有给出A的完整声明,没有办法提前声明A :: B
  • 可扩展性:除非您是A的所有者,否则不可能添加另一个类A :: C
  • 代码详细程度:将类放入类只会使头部变大。 你仍然可以把它分成多个声明,但是没有办法使用名字空间的别名,导入或使用。

作为结论,除非是例外(例如,嵌套类是嵌套类的一个亲密部分…即使如此…),但我认为正常代码中的嵌套类没有意义,因为缺陷大小超出了优势。

此外,它闻起来像一个笨拙的尝试来模拟命名空间,而不使用C ++命名空间。

在亲的方面,你隔离这个代码,如果是私有的,使其不可用,但从“外”类…

嵌套枚举

优点:一切。

Con:没什么。

事实上,枚举项目将污染全球范围:

 // 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 ; 

正是为了这样的问题。

一个对于大型项目来说可能成为一件大事的骗局是,不可能为嵌套类或枚举做一个前向声明。

如果你永远不会使用依赖类,而是使用独立类的实现,嵌套类是好的,在我看来。

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

看来你应该使用命名空间而不是类来像这样相互关联的东西进行分组。 我在嵌套类中看到的一个问题是,当你search一个节时,你会得到一个非常大的源文件。

本身没有优点和缺点使用嵌套的公共C ++类。 只有事实。 这些事实是由C ++标准强制的。 嵌套的公共C ++类的事实是一个专业还是一个骗局取决于你正在试图解决的特定问题。 你给出的例子不允许判断嵌套类是否合适。

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

  1. B成为A的朋友
  2. 使B成为A的嵌套类
  3. 使B需要的方法和属性成为A的公共成员。

在这种情况下,违反封装的是#3,因为A控制了他的朋友和他的嵌套类,而不是控制他的公共方法或访问他的公共属性的类。

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

索姆有关嵌套公共课程的其他事实:

  • A的范围是B的符号查找的候选者 :如果你不想要这个,使B成为A的朋友而不是嵌套类。 但是,有些情况下,您只需要这种符号查找。
  • A :: B不能正向声明: AA :: B紧密耦合。 能够使用A :: B而不知道A只会隐藏这个事实。

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

paercebal说的一切,我会说嵌套枚举。

WRT嵌套类,我常见的和几乎唯一的用例是当我有一个类操纵一个特定types的资源,我需要一个数据类代表特定的资源。 在你的情况下,output_tray可能是一个很好的例子,但是我通常不会使用嵌套类,如果类将有任何方法将被从包含的类以外,或主要是一个数据类。 我通常也不会嵌套数据类,除非包含的类在包含类之外没有被直接引用。

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

希望这可以帮助。 🙂

请记住,您以后可以始终将嵌套类升级为顶级类,但是如果不破坏现有代码,则可能无法做相反的事情。 因此,我的build议是首先使它成为一个嵌套类,如果它开始成为一个问题,那么将它作为下一个版本中的顶级类。

对我来说,把它放在外面的一个重要原因是它成为了全局命名空间的一部分。 如果枚举或相关类仅仅适用于它所在的类,那么它是有意义的。 所以在打印机的情况下,包括打印机在内的所有东西都知道对PRINTER_TYPE有完全的访问权限,在那里它并不需要知道。 我不能说我曾经使用过一个内部类,但是对于一个枚举来说,这看起来更合乎逻辑。 正如另一个海报指出的那样,使用名称空间来分组类似的项目也是一个好主意,因为堵塞全局名称空间确实是一件坏事。 我以前曾经在大量的项目上工作过,只是在全局命名空间中创build一个自动完成列表需要20分钟。 在我看来,嵌套枚举和命名空间类/结构可能是最干净的方法。

我同意那些主张在一个类中embedded你的枚举的post,但是有些情况下不这样做会更有意义(但请至less把它放在一个名字空间中)。 如果多个类使用不同类中定义的枚举,那么这些类直接依赖于其他具体类(拥有枚举)。 这肯定是一个devise上的缺陷,因为这个类将负责这个枚举以及其他的责任。

所以,是的,如果其他代码只使用该枚举直接与该具体类进行交互,则将该枚举embedded到类中。 否则,找一个更好的地方来保持枚举,如命名空间。

如果将枚举放入类或名称空间,当您试图记住枚举名称时,intellisense将能够为您提供指导。 肯定是一件小事,但有时小事很重要。

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

我可以看到一个嵌套的类,可以更好地使用generics编程。

如果小class是在大class之外定义的,那么你可以把大class制作成class级模板,并在将来与大class级一起使用你可能需要的任何“小class”。

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

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

(但也许有办法?)