【问题标题】:Namespace-level access命名空间级访问
【发布时间】:2013-03-08 20:43:19
【问题描述】:

我有以下情况:

namespace MyFramework {
  class A {
    void some_function_I_want_B_to_use() {}
  };
  class B {
    B() {
      some_function_I_want_B_to_use() {}
    }
  };
}

我希望 some_function_I_want_B_to_useMyFramework 命名空间之外不可见,但我确实希望它对 MyFramework 内部的任何人可见(或者,仅对 B 类可见也可以)。我有很多这样的方法,是从 MyFramework 的公共 API 中隐藏它们以使 MyFramework 中的所有类成为朋友的唯一方法吗?我也在考虑将所有“低级”类放在 B 中,但我不想走那条路,直到我确定它能够从 B 内部而不是从 B 内部访问所有 A 的方法在 MyFramework 之外。

重申一下,我有一个在一个命名空间中创建的框架,每个类都有对使用该框架的公众有用的方法。但是,每个类也有一些使公共 API 复杂化但框架正常运行所必需的方法。

【问题讨论】:

  • “可见”是什么意思?如果在头文件中可以找到函数名,但函数是private,是否可见?
  • 否(出于我的目的)。我希望能够将“公共” api 列为唯一的公共方法。例如。拥有 3 个公共方法可以清楚地使用类,但拥有 20 多个方法会使类的使用不那么明显
  • some_function_I_want_B_to_use需要是A的方法吗?或者它可以是 MyFramework 中的命名空间函数吗?
  • 嗯...有趣的想法。许多“some_function...”选项都在访问它们各自类中的私有变量。但是,我可能会使用 getter 来删除这个要求,并将其中的一些拉入命名空间本身。如果没有更好的方法,可能是一种有效的方法:-)
  • 我忘记了这是否会授予类访问彼此的私有数据成员的权限,但是如果 MyFramework 是一个类,并且在它之下是每个类(适当的成员是私有的)呢?或者,我认为外观(设计模式)正是针对这种情况的;如果您愿意为每个类创建一个公共外观,这是一个不错的选择

标签: c++ namespaces access-modifiers


【解决方案1】:

我希望some_function_I_want_B_to_useMyFramework 命名空间之外不可见,但我确实希望它对MyFramework 内部的任何人可见。

总而言之,您需要类似于 Java 中的包的东西。

不幸的是,使用命名空间不可能。命名空间中包含的每个类都可以从命名空间的外部访问:命名空间是开放的。

解决方案通常是为实现细节添加另一个命名空间:

namespace MyFramework
{
    // Implementation details
    // Should not be used by the user
    namespace detail
    {
        class A
        {
            public:
                void func();
        };
    }

    class B
    {
        public:
            B()
            {
                A a;
                a.func();
            }
    };
}

不要忘记添加注释说明detail 命名空间不被用户使用。

【讨论】:

    【解决方案2】:

    通用约定,例如在 Boost 中,是一个名为 detail 的嵌套命名空间。

    如果您想实施可访问性,您始终可以使用嵌套的class,称为detail。该类提供可访问性检查,但缺乏像命名空间那样的可扩展性。但是,detail 范围很少需要扩展。

    所以,尽管丑陋,

    namespace my_framework {
        class detail
        {
        private:
            static void some_function_I_want_B_to_use() {}
    
        public:
            class A
            {};
    
            class B
            {
                B() { some_function_I_want_B_to_use(); }
            };
        };
    
        typedef detail::A A;        // "using detail::A"
        typedef detail::B B;        // "using detail::B"
    }  // namespace my_framework
    

    顺便提一下,B 类(直接来自问题)有一个私有的默认构造函数,因此不能创建它的实例。

    【讨论】:

      【解决方案3】:

      Pimpl idiom,通常称为编译防火墙,正是您要找的。整个Qt都是用这个成语实现的。

      // A.hpp
      namespace MyFramework {
        class A {
        private:
          class Private;
      
          Private* implementation;
        };
      }
      
      // A_Private.hpp
      #include "A.hpp"
      
      namespace MyFramework {
        class A::Private {
        public:
          void some_function_I_want_B_to_use() {}
        };
      }
      
      // A.cpp
      #include "A_Private.hpp"
      
      namespace MyFramework {
      A::A() {
        implementation->some_function_I_want_B_to_use();
      }
      }
      
      // B.hpp
      #include "A.hpp"
      
      namespace MyFramework {
        class B {
          B();
      
          A a;
        };
      }
      
      // B.cpp
      #include "A_Private.hpp"
      
      namespace MyFramework {
      B::B() {
        a.implementation->some_function_I_want_B_to_use();
      }
      }
      

      注意:当然A_Private.hpp 不会进入你的框架最终发行版的include 目录,即它仍然是package private 你需要的。 p>

      这个例子非常基础。当然,它可以做得更先进、更健壮。此外,Pimpl 还有许多其他优点。有关所有这些信息,请参阅:

      【讨论】:

      • 如果只需要一个标头模块怎么办?
      • @Cheers 和 hth。 - Alf,那么,你运气不好,这就是Boost 使用detail 命名空间约定的确切原因(另一个原因是轻微的开销)。但是作者没有提供这样的要求,因此这个解决方案非常适合他的问题。
      猜你喜欢
      • 2016-03-05
      • 1970-01-01
      • 2012-08-13
      • 2010-11-22
      • 2015-01-08
      • 2012-03-26
      • 1970-01-01
      • 2018-09-16
      • 2012-09-04
      相关资源
      最近更新 更多