【问题标题】:C++ a class to be used only by another classC++ 一个只能被另一个类使用的类
【发布时间】:2010-12-20 15:45:17
【问题描述】:

我正在构建一个类(A 类),它需要能够在其操作过程中创建另一个类(B 类)的多个实例,但 B 类仅由少数成员函数使用A级,从未在课堂外使用过。如何最好地定义 B 类?使其成为 A 类的私人成员是否可行/合理?这是嵌套类的预期目的,还是我放弃了构造的精神?

谢谢, 悦

编辑:进一步考虑,我并不是在询问最佳实践,因为这是针对个人项目的。从封装的角度来看,我想将 B 类包含为 A 类的成员 - 完全从属的类实际上应该是其所属类的一部分,这似乎是合理的。

我想知道这是否是嵌套类的合理用例?如果不是,嵌套类的目的是什么?

【问题讨论】:

    标签: c++ class nested-class


    【解决方案1】:

    一种的可能性是在放置类的命名空间内定义一个名为detail 的命名空间。例如

    // public_namespace_detail.hpp
    namespace public_namespace
    {
        namespace detail
        {
            class B
            {
              ...
            };
    
        }
    }
    
    // public_namespace.hpp
    #include "public_namespace_detail.hpp"
    
    namespace public_namespace
    {
        class A
        {
           detail::B b;
           ...       
        };
    }
    

    【讨论】:

      【解决方案2】:

      我只会让class Bclass A 完全无关——如果没有别的,如果您可以分别测试class Aclass B,它将更容易编写测试。如果您不想走那条路,请通过定义class B,使其具有私有构造函数,然后将class A 设为friend,以防止除class A 之外的任何人实例化class B

      【讨论】:

      • 从编码的角度来看,我什至不担心别人实例化它,这都是私人项目,只是封装的问题。将一个与另一个类天生相关的类声明为一个完全独立的对象感觉是错误的。我的问题与其说是关于最佳实践,不如说是关于这是否是对嵌套类的合理使用。我意识到这不是我问的,我会编辑我的问题。
      • @wyatt:恕我直言,C++ 中没有合理使用嵌套类。
      • @Billy ONeal 如果它们不再是可行的结构,它们最初的用途是什么?
      • @Wyatt:C++ 从什么时候开始阻止你做不可行的事情?我的猜测是它们被添加是因为 Java 有它们。
      • @Billy:C++ 嵌套类与 Java 内部类几乎没有共同之处(Java 本身没有嵌套类,尽管静态内部类非常接近)
      【解决方案3】:

      您有多种选择:

      1. 私有继承:class A : private B {};

      2. 嵌套类:class A { class B { /* etc */ }; };

      3. A 类到 B 类的优秀私人成员:class A { B b; };

      如果您 100% 确定在外部不需要嵌套类,我个人会选择嵌套类。

      【讨论】:

      • 私有继承根本不是一个合适的选择。他并没有试图塑造一种“曾经”的关系。
      • @Brent: private 继承是 implemented-in-terms-of,而不是 was-a
      • 只是为了确定,如果 B 类嵌套在 A 类中,它的行为将与全局声明的类完全相同,前提是它是从 A 类中引用的?我似乎找不到很多讨论嵌套类的好参考。
      • 私有继承和私有成员可能不是合适的选项,不是因为任何 is-a 关系,而是因为它们强制每个 A 实例与B 的一个实例。
      • @wyatt 正确,AraK 的命名空间解决方案也不错,完全忘记了。
      【解决方案4】:

      对我来说,一般的经验法则是,如果我发现继承有困难的问题,那么我可能以错误的方式看待问题。

      有没有一种方法可以重组程序以减少类的“耦合”? IE。您能否将引用 B 类的函数移出 A 类(并将它们放在 B 中)?

      【讨论】:

      • 他的问题与继承无关。
      • 这两个类可以很容易地分开,但一个只对另一个有用。这两个类之间的关系非常类似于字符串和正则表达式类的关系——A 类是字符串,B 类是编译的正则表达式语句。我可以单独实现它们,但是由于 B 类只对 A 类有用,而 A 类本身就是一个相当具体的类,这似乎有点傻。
      • 请注意,我并不是要混淆课程的目的,它只是有点令人费解,并不是非常重要。
      【解决方案5】:

      我会将它移到 B 之外,否则它将通过 A 的头文件暴露给其他类(不管你喜欢与否)。换句话说,如果您更改 B 的实现,则 A 的客户端必须重新编译 - 因为 B 是在 A 内部声明的。

      我的项目结构应该明确B的头文件不应该被其他类使用。例如,我有一个名为“exports”的文件夹,其中放置了我打算在项目外部共享的所有头文件。显然那里不会找到 B 的标头。

      在另一种不使用头文件的语言中,例如 C#,如果 B 相当小,我会随便将 B 放在 A 中 - 可能不超过 6-10 行声明。

      【讨论】:

      • A 中定义B 与使B 成为A 的嵌套类(因此可以访问其私有成员)是一个单独的问题。 C++ 不是 Java 或 C#。
      • @Ben:我只解决嵌套类(这是问题的主题)。实际上,嵌套类无法访问封闭类的私有成员。见这里:publib.boulder.ibm.com/infocenter/comphelp/v8v101/…
      • 您在回答中所说的几乎所有内容都是基于B 的定义在A 的头文件中...但这不是嵌套类所必需的。
      • 此外,从一些不起眼的编译器中引用文档也无济于事。根据 C++0x 草案,嵌套类是一个成员,因此具有与任何其他成员相同的访问权限。。如果这种行为对 C++0x 来说是新的,我会感谢您使用的早期标准(不是 IBM 编译器)的引用。
      • 嵌套类可以访问封闭类的私有成员。请参阅我的答案中的新代码示例。您提到的 IBM 行为不符合标准。
      【解决方案6】:

      是的,这里可以使用嵌套类。

      请注意,为了使代码井井有条,我不会将B 的定义放在A 中。而是:

      class A
      {
          class B;
      };
      
      class A::B
      {
      };
      

      除其他外,这允许将类 A::B 的定义放在 A 的实现文件中。

      编辑:由于嵌套类是否可以访问包含类的私有成员似乎有些混淆,我提供了一个代码 sn-p 来证明它可以:

      class A
      {
          int x;
      
          class B
          {
              int func(A* p) { return p->x; }
          };
      };
      

      Variant without inline definition of A::B, also accepted:

      class A
      {
          int x;
      
          class B;
      };
      
      class A::B
      {
          int func(A* p) { return p->x; }
      };
      
      • Comeau:接受(两种变体)

      您的 Comeau C/C++ 测试结果如下 如下:

      Comeau C/C++ 4.3.10.1(2008 年 10 月 6 日) 11:28:09) 用于 ONLINE_EVALUATION_BETA2 版权所有 1988-2008 Comeau Computing。 版权所有。模式:严格 错误 C++ noC++0x_extensions

      在严格模式下,使用 -tused,编译 成功了(但请记住,Comeau 在线编译器不链接)。 使用 C++0x 扩展编译 已禁用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多