使用嵌套 C++ 类和枚举的优缺点?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/216748/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pros and cons of using nested C++ classes and enumerations?
提问by Rob
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:
使用嵌套的公共 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;
Alternatively:
或者:
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?
那么,你更喜欢哪个,为什么?
回答by paercebal
Nested classes
嵌套类
There are several side effects to classes nested inside classes that I usually consider flaws (if not pure antipatterns).
嵌套在类中的类有几个副作用,我通常认为这些是缺陷(如果不是纯粹的反模式)。
Let's imagine the following code :
让我们想象以下代码:
class A
{
public :
class B { /* etc. */ } ;
// etc.
} ;
Or even:
甚至:
class A
{
public :
class B ;
// etc.
} ;
class A::B
{
public :
// etc.
} ;
So:
所以:
- 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 allsymbols 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.
- 特权访问:A::B 对 A 的所有成员(方法、变量、符号等)具有特权访问权限,这削弱了封装性
- A 的范围是符号查找的候选对象:来自 B 内部的代码会将A 中的所有符号视为符号查找的可能候选对象,这可能会混淆代码
- 前向声明:如果不提供 A 的完整声明,就无法前向声明 A::B
- 可扩展性:除非您是 A 的所有者,否则不可能添加另一个类 A::C
- 代码冗长:将类放入类只会使标题变大。您仍然可以将其分成多个声明,但无法使用类似名称空间的别名、导入或使用。
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.
作为结论,除非例外(例如嵌套类是嵌套类的亲密部分......即使如此......),我认为在正常代码中嵌套类没有意义,因为缺陷在数量级上超过了感知优势.
Furthermore, it smells as a clumsy attempt to simulate namespacing without using C++ namespaces.
此外,它闻起来像是在不使用 C++ 命名空间的情况下模拟命名空间的笨拙尝试。
On the pro-side, you isolate this code, and if private, make it unusable but from the "outside" class...
在专业方面,您隔离此代码,如果是私有的,则使其无法使用,但来自“外部”类...
Nested enums
嵌套枚举
Pros: Everything.
优点:一切。
Con: Nothing.
康:没什么。
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 ;
Note that C++0x defined the class enum:
请注意,C++0x 定义了类枚举:
enum class Value { empty, undefined, defined } ;
enum class Glass { empty, half, full } ;
// Value e = Value::empty ;
// Glass f = Glass::empty ;
exactly for this kind of problems.
正是针对这类问题。
回答by Adam Rosenfield
One con that can become a big deal for large projects is that it is impossible to make a forward declaration for nested classes or enums.
对于大型项目来说,一个可能成为大问题的缺点是不可能为嵌套类或枚举进行前向声明。
回答by Oswald
There are no pros and cons per se of using nested public C++ classes. There are only facts. Those facts are mandated by the C++ standard. Whether a fact about nested public C++ classes is a pro or a con depends on the particular problem that you are trying to solve. The example you have given does not allow a judgement about whether nested classes are appropriate or not.
使用嵌套的公共 C++ 类本身没有优缺点。只有事实。这些事实是 C++ 标准规定的。关于嵌套公共 C++ 类的事实是赞成还是反对取决于您要解决的特定问题。您给出的示例不允许判断嵌套类是否合适。
One fact about nested classes is, that they have privileged access to all members of the class that they belong to. This is a con, if the nested classes does not need such access. But if the nested class does not need such access, then it should not have been declared as a nested class. There are situations, when a class Awants to grant privileged access to certain other classes B. There are three solutions to this problem
关于嵌套类的一个事实是,它们具有访问它们所属类的所有成员的特权。这是一个骗局,如果嵌套类不需要这样的访问。但是如果嵌套类不需要这样的访问,那么它就不应该被声明为嵌套类。在某些情况下,类A想要授予某些其他类B 的特权访问权限。这个问题有三种解决方案
- Make Ba friend of A
- Make Ba nested class of A
- Make the methods and attributes, that Bneeds, public members of A.
- 让B成为A的朋友
- 使B成为A的嵌套类
- 使B需要的方法和属性成为A 的公共成员。
In this situation, it's #3 that violates encapsulation, because Ahas control over his friends and over his nested classes, but not over classes that call his public methods or access his public attributes.
在这种情况下,#3 违反了封装,因为A可以控制他的朋友和他的嵌套类,但不能控制调用他的公共方法或访问他的公共属性的类。
Another fact about nested classes is, that it is impossible to add another class A::Cas a nested class of Aunless you are owner of A. However, this is perfectly reasonable, because nested classes have privileged access. If it were possible to add A::Cas a nested class of A, then A::Ccould trick Ainto granting access to privileged information; and that yould violate encapsulation. It's basically the same as with the friend
declaration: the friend
declaration does not grant you any special privileges, that your friend is hiding from others; it allows your friends to access information that you are hiding from your non-friends. In C++, calling someone a friend is an altruistic act, not an egoistic one. The same holds for allowing a class to be a nested class.
关于嵌套类的另一个事实是,除非您是A 的所有者,否则不可能将另一个类A::C添加为A的嵌套类。但是,这是完全合理的,因为嵌套类具有特权访问权限。如果有可能增加一个中:C为嵌套类的一个,然后一中:C可以欺骗一个为授权访问机密信息; 并且你会违反封装。它与声明基本相同:friend
friend
声明不会授予您任何特权,即您的朋友对他人隐瞒;它允许您的朋友访问您对非朋友隐藏的信息。在 C++ 中,称某人为朋友是一种利他行为,而不是自私自利的行为。允许类成为嵌套类也是如此。
Som other facts about nested public classes:
关于嵌套公共类的其他一些事实:
- A's scope is candidate for symbol lookup of B: If you don't want this, make Ba friend of Ainstead of a nested class. However, there are cases where you want exactly this kind of symbol lookup.
- A::Bcannot be forward-declared: Aand A::Bare tightly coupled. Being able to use A::Bwithout knowing Awould only hide this fact.
- A 的范围是 B 的符号查找的候选对象:如果您不想要这样,请将B设为A的朋友而不是嵌套类。但是,在某些情况下,您确实需要这种符号查找。
- A::B不能向前声明:A和A::B是紧密耦合的。能够在不知道A 的情况下使用A::B只会隐藏这个事实。
To summarize this: if the tool does not fit your needs, don't blame the tool; blame yourself for using the tool; others might have different problems, for which the tool is perfect.
总结一下:如果工具不适合你的需求,不要责怪工具;责备自己使用该工具;其他人可能有不同的问题,该工具是完美的。
回答by Paul Nathan
If you're never going to be using the dependent class for anything but working with the independent class's implementations, nested classes are fine, in my opinion.
如果除了使用独立类的实现之外,您永远不会将依赖类用于任何事情,那么在我看来,嵌套类很好。
It's when you want to be using the "internal" class as an object in its own right that things can start getting a little manky and you have to start writing extractor/inserter routines. Not a pretty situation.
当您想使用“内部”类作为对象本身时,事情可能会开始变得有点麻烦,您必须开始编写提取器/插入器例程。不是一个漂亮的情况。
回答by carson
It seems like you should be using namespaces instead of classes to group like things that are related to each other in this way. One con that I could see in doing nested classes is you end up with a really large source file that could be hard to grok when you are searching for a section.
似乎您应该使用名称空间而不是类来对以这种方式相互关联的事物进行分组。我在执行嵌套类时可以看到的一个缺点是,您最终会得到一个非常大的源文件,当您搜索某个部分时,它可能很难理解。
回答by Nick
paercebal said everything I would say about nested enums.
paercebal 说了我想说的关于嵌套枚举的所有内容。
WRT nested classes, my common and almost sole use case for them is when I have a class which is manipulating a specific type of resource, and I need a data class which represents something specific to that resource. In your case, output_tray might be a good example, but I don't generally use nested classes if the class is going to have any methods which are going to be called from outside the containing class, or is more than primarily a data class. I generally also don't nest data classes unless the contained class is not ever directly referenced outside the containing class.
WRT 嵌套类,我对它们的常见且几乎唯一的用例是当我有一个操作特定类型资源的类时,我需要一个代表该资源特定内容的数据类。在您的情况下, output_tray 可能是一个很好的例子,但如果类将有任何将从包含类外部调用的方法,或者不仅仅是一个数据类,我通常不会使用嵌套类。我通常也不嵌套数据类,除非所包含的类从未在包含类之外直接引用。
So, for example, if I had a printer_manipulator class, it might have a contained class for printer manipulation errors, but printer itself would be a non-contained class.
因此,例如,如果我有一个 printer_manipulator 类,它可能有一个包含打印机操作错误的类,但打印机本身将是一个非包含类。
Hope this helps. :)
希望这可以帮助。:)
回答by Eric G.
Remember that you can always promote a nested class to a top-level one later, but you may not be able to do the opposite without breaking existing code. Therefore, my advice would be make it a nested class first, and if it starts to become a problem, make it a top-level class in the next version.
请记住,您始终可以稍后将嵌套类提升为顶级类,但您可能无法在不破坏现有代码的情况下执行相反的操作。因此,我的建议是首先将其设为嵌套类,如果它开始成为问题,则在下一个版本中将其设为顶级类。
回答by Yaroslav Nikitenko
I can see a con for nested classes, that one may better use generic programming.
我可以看到嵌套类的一个骗局,人们可能会更好地使用泛型编程。
If the little class is defined outside the big one, you can make the big class a class template and use any "little" class you may need in the future with the big class.
如果小类是在大类之外定义的,您可以使大类成为类模板,并在大类中使用您将来可能需要的任何“小”类。
Generic programming is a powerful tool, and, IMHO, we should keep it in mind when developing extensible programs. Strange, that no one has mentioned this point.
泛型编程是一个强大的工具,恕我直言,我们在开发可扩展程序时应该牢记这一点。奇怪了,居然没有人提到这一点。
回答by Pat Notz
I agree with the posts advocating for embedding your enum in a class but there are cases where it makes more sense to not do that (but please, at least put it in a namespace). If multiple classes are utilizing an enum defined within a different class, then those classes are directly dependent on that other concrete class (that owns the enum). That surely represents a design flaw since that class will be responsible for that enum as well as other responsibilities.
我同意那些主张将枚举嵌入到类中的帖子,但在某些情况下,不这样做更有意义(但请至少将其放在命名空间中)。如果多个类使用在不同类中定义的枚举,则这些类直接依赖于其他具体类(拥有该枚举)。这肯定代表了一个设计缺陷,因为该类将负责该枚举以及其他职责。
So, yeah, embed the enum in a class if other code only uses that enum to interface directly with that concrete class. Otherwise, find a better place to keep the enum such as a namespace.
所以,是的,如果其他代码仅使用该枚举直接与该具体类交互,则将枚举嵌入到一个类中。否则,找一个更好的地方来保存枚举,比如命名空间。
回答by Mark Ransom
If you put the enum into a class or a namespace, intellisense will be able to give you guidance when you're trying to remember the enum names. A small thing for sure, but sometimes the small things matter.
如果您将枚举放入类或命名空间中,当您尝试记住枚举名称时,智能感知将能够为您提供指导。当然是小事,但有时小事也很重要。