1

问题:是否可以在隐藏该标头中定义的其他名称空间/类的同时从标头访问特定类?

例如,假设我有头文件 --结果.hpp

// outcome.hpp
namespace sports { namespace outcome {
  class Injury {};
  class Success {};
}}

在另一个头文件 - api.hpp - 我希望在sports::outcome::Injury无法sports::outcome::Success访问包含api.hpp的文件的情况下使用。那可能吗?如果是这样,我该如何实现?

PS 在实际代码中,api.hpp包含将调用Injury类方法的模板化方法,因此前向声明是不够的。


我的尝试:

在我的无知中,我试图通过将 放置include在内部命名空间中来实现这一点。这是一个SSCCE

// api.hpp
namespace sports { namespace api {
  namespace internal {
    #include "outcome.hpp"  // I'm trying to hide symbols within this header
    using sports::outcome::Injury;
  } 

  class Boxing {
    private:
      internal::Injury sustained;
  };
}

当它奏效时,我过早地庆祝:

// This cpp file compiles file   \o/
#include "api.hpp"
int main(int argc, char *argv[]) {
  sports::api::Boxing b;  
  // sports::outcome not accessible
}

它是如何失败的:

如果将标准库中的容器用作result.hpp中的类成员,事情就会崩溃。例如,使用这个版本:

// outcome.hpp
#include <vector>
namespace sports { namespace outcome {

  class Injury {
    private:
      std::vector x;
  };

// ...
}}

编译失败并出现以下错误:

在 /usr/include/c++/4.6/ext/new_allocator.h:34:0 包含的文件中,
                 来自 /usr/include/c++/4.6/x86_64-linux-gnu/./bits/c++allocator.h:34,
                 来自 /usr/include/c++/4.6/bits/allocator.h:48,
                 来自 /usr/include/c++/4.6/vector:62,
                 从结果.hpp:1,
                 来自 api.hpp:5,
                 来自 main.cpp:1:
/usr/include/c++/4.6/new:93:54: 错误:'void* sports::api::internal::operator new(sports::api::internal::std::size_t)' 可能不是在命名空间中声明
/usr/include/c++/4.6/new:94:56: 错误:'void* sports::api::internal::operator new [](sports::api::internal::std::size_t)' 可能不在命名空间内声明
/usr/include/c++/4.6/new:95:35: 错误:'void sports::api::internal::operator delete(void*)' 不能在命名空间中声明
/usr/include/c++/4.6/new:96:37: 错误:'void sports::api::internal::operator delete [](void*)' 不能在命名空间中声明
/usr/include/c++/4.6/new:97:62: 错误: 'void* sports::api::internal::operator new(sports::api::internal::std::size_t, const sports:: api::internal::std::nothrow_t&)' 不能在命名空间中声明
/usr/include/c++/4.6/new:98:64: 错误:'void* sports::api::internal::operator new [](sports::api::internal::std::size_t, const sports ::api::internal::std::nothrow_t&)' 不能在命名空间中声明
/usr/include/c++/4.6/new:99:58: 错误:'void sports::api::internal::operator delete(void*, const sports::api::internal::std::nothrow_t&)'不能在命名空间中声明
/usr/include/c++/4.6/new:100:60: 错误:'void sports::api::internal::operator delete [](void*, const sports::api::internal::std::nothrow_t& )' 不能在命名空间中声明
/usr/include/c++/4.6/new:103:57: 错误:'void* sports::api::internal::operator new(sports::api::internal::std::size_t, void*)'不能在命名空间中声明
/usr/include/c++/4.6/new:104:59: 错误:'void* sports::api::internal::operator new [](sports::api::internal::std::size_t, void* )' 不能在命名空间中声明
/usr/include/c++/4.6/new:107:52: 错误:'void sports::api::internal::operator delete(void*, void*)' 不能在命名空间中声明
/usr/include/c++/4.6/new:108:52: 错误:'void sports::api::internal::operator delete [](void*, void*)' 不能在命名空间中声明

我显然做错了。建议和良好的告白将不胜感激。

4

2 回答 2

1

您可以使用 using 声明将名称从命名空间导入到不同的命名空间。

namespace sports {
  using sports::outcome::Injury;
};

在您的示例中,很多事情都是错误的。尤其是包含位置不佳,并且您缺少包含警卫。

// file1.h
#ifndef FILE1_h
#define FILE1_h

namespace sports { namespace outcome {
  class Injury;
}}
#endif

// api.h   
#ifndef API_H
#define API_H

#include <file1.h>

namespace sports {
  using sports::outcome::injury;
}

#endif

包含的文件api.h现在可以访问:

sports::injury x;

仅包含的文件file1.h只能访问:

sports::outcome::injury x;
于 2012-11-14T16:19:41.943 回答
0

如果我正确理解您的意图,那么您想要“私有”或“内部”命名空间之类的东西吗?恕我直言,这在 C++ 中是不可能的。

您可以使用一个类来执行此操作并将内部类定义作为嵌套类放置在那里,您的 api 命名空间可以类似地实现,将其他类公开为公共类型定义,前提是 api 是内部类的朋友。

namespace sports
{
    class api;

    class outcome
    {
        friend class api;

        // Internal class definitions
        class Boxing
        {
        };
    };

    class api
    {
    public:
        typedef outcome::Boxing Boxing;
    }
}
于 2012-11-14T16:31:55.023 回答