【问题标题】:forward declare a C typedef in a C++ header [closed]在 C++ 标头中前向声明 C typedef [关闭]
【发布时间】:2016-12-17 11:40:43
【问题描述】:

我为 C API 编写了一个 C++ 包装类。

我的包装类有一个在原始 API 中使用的 typedef 结构的私有实例成员。我不想修改API头文件,但我也想隐藏原始API的所有痕迹,所以我不想在包装类的头文件中包含原始API头文件。

我可能忽略了一些非常简单的东西,但我没有找到它。 PIMPL 是一种选择,但我更愿意在为一件小事重构整个代码库之前寻找替代方案。

wrapper.hpp

class myWrapper
{
public:
    myWrapper();

private:
    originalTypedef *original; // forward declaration needed for originalTypedef 
};

wrapper.cpp

#include "wrapper.hpp"
#include "originalAPI.h"

myWrapper::myWrapper()
{
    original = originalAPI_get();
}

Main.cpp

#include "wrapper.hpp"

int main()
{
    myWrapper wrapper = new myWrapper();
}

【问题讨论】:

  • 你能给我们一个minimal reproducible example好吗?
  • 除了我提供的东西?我提供的内容更加连贯。
  • @user4581301 这是一个选项,但我想在重构代码以实现 PIMPL 之前寻求替代方案。
  • 这当然不是minimal reproducible example!请至少提供一个不错的在线编译器的链接。

标签: c++ private encapsulation public


【解决方案1】:

我能很快想到的选项:

  1. 您可以只重复 myWrapper.h 中 C API 中的 typedef

    typedef struct the_original_struct_type originalTypedef;
    
  2. 在调用 C API 之前,您可以在 myWrapperreinterpret_castoriginalTypedef* 中使用 void* 作为成员变量。

    class myWrapper
    {
       private:
          void* original;
    };
    

【讨论】:

  • 正在写这个答案,但这是第一个。请注意,选项 (1) 仅适用于 C API 预计不会在未来发生变化的情况(因为您必须更新包装器)。此外,您可能需要使用条件宏“IS_ORIGINAL_C_API_INCLUDED”等来防止 myWrapper.cpp 中出现多个定义错误。
  • #2 会起作用,但你会丢失所有类型信息,所以要小心转换。
【解决方案2】:

一个奇特的解决方案是编写一个代码生成器,它读取 original_c_api.h,并输出一个文件 original_c_api_types.h,该文件仅包含结构定义、类型等但不包含任何函数,以及一个包含 original_c_api_functions.h 的文件函数声明。然后 wrapper.h 包含 original_c_api_types.h 并且 wrapper.cpp 包含 wrapper.h 和 original_c_api_functions.h。代码生成器应该作为 makefile 中的目标运行。

当然,如果您有权修改原始 C api 文件,这是最简单的解决方案。

【讨论】:

    【解决方案3】:

    您正在寻找类似于 pImpl 模式的东西 - 您提供了一个 C++ API,并且从客户端混淆了实现:

    头文件

    // forward declare obfuscated implementation
    // we can do this because we're only using a ptr
    class Implementation;
    
    class Wrapper
    {
       public:
          Wrapper();
          ~Wrapper();
          void doSomething();
    
       private:
          Implementation * pImpl;
      };
    

    .cpp 文件

      #include "originalAPI.h"
      class Implementation
      {
         public:
          void doSomething()
          {
             OriginalAPI_DoSomething();
          }
       };
    
       Wrapper::Wrapper()
       {
         this->pImpl = new Implementation();
       }
    
       Wrapper::~Wrapper()
       {
          delete pImpl;
       }
    
       void Wrapper::doSomething()
       {
          pImpl->doSomething;
       }
    

    【讨论】:

    • 我很欣赏这个答案,但我正在寻找 PIMPL 的替代品。代码库已经存在,这样做需要对一件小事进行大规模重构
    • 好的,所以只需将 originalTypeDef 声明为它的确切类型 - 但不要在标题中定义它。这样,您就不需要在包装头中包含原始 api 头了。
    猜你喜欢
    • 1970-01-01
    • 2013-06-02
    • 2010-10-22
    • 2020-03-11
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    相关资源
    最近更新 更多