4

我有以下情况:

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

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

4

3 回答 3

4

我希望在命名空间some_function_I_want_B_to_use之外不可见MyFramework,但我确实希望它对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用户不得使用命名空间。

于 2013-03-19T23:49:45.987 回答
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 类(直接来自问题)有一个私有默认构造函数,因此不能创建它的实例。

于 2013-03-20T00:06:59.320 回答
2

Pimpl idiom,通常称为Compilation Firewall,是您正在寻找的。整个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框架最终分发的目录,即它根据您的需要保持包私有。

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

于 2013-03-20T00:10:54.503 回答