【问题标题】:How to include the two different versions of the same header?如何包含同一标题的两个不同版本?
【发布时间】:2013-07-08 10:55:55
【问题描述】:

我正在编写从专有文件格式到更通用的文件转换代码。我的目标是支持制造商文件格式的多个版本。

我有多个版本的相同专有标头。标头定义了构成主文件标头的各种结构(文件只是一个大标头,后跟原始数据)。

我需要读取源文件的前 4 个字节以确定文件版本。反过来,文件版本告诉我使用哪个版本的 C 结构创建文件。

问题是:

  1. 我无法修改专有标头
  2. 标头不使用命名空间或类
  3. 头文件中定义了很多宏

可能的解决方案:

  • 为每种文件版本类型构建不同的转换器二进制文件:-(
    • 给用户和开发者带来不便
  • 为每个版本动态加载库
    • 转换器是面向插件的,所以已经有很多这样的事情发生了

我尝试过使用命名空间进行黑客攻击:

namespace version1 {
    #include "version1.h"
}

namespace version2 {
    #include "version2.h"
}

int main (void) {
    version1::header *hdr = new version1::header;
    return 0;
}

但这不会起作用,因为包含保护,并且每个标头中都重新定义了多个宏。

有没有优雅的方法来处理这个问题?

【问题讨论】:

  • 标题——C 怎么样?您是否只使用标题,没有库或支持它们的 .c.cpp 文件?您说您不能修改标头:您可以将标头作为输入并代码生成要编译的衍生产品吗?
  • 它们是纯 C 头文件。甚至没有任何函数声明,只有 C 结构。
  • @MatsPetersson 可能有一个合理的方法。

标签: c++ header include version conflict


【解决方案1】:

您可以使用两个不同的源文件以及前向声明:

// Forward declare in main.cpp:

namespace version1
{
   struct header;
}

namespace version2
{
   struct header;
}

// version1.cpp:

namespace version1
{
      #include <version1.h>
}

version1::header* new_v1_header()
{
   return new version1::header;
}

// other functions using `version1::header`

// version2.cpp:

namespace version2
{
      #include <version2.h>
}

version2::header* new_v2_header()
{
   return new version2::header;
}

// other functions using `version2::header`

另一种选择是实现一个包装类,它的基类只是一个空壳:

class header_base
{
     virtual int func1(char *stuff) = 0; 
     ... many other virtual functions. 
};

// Create implementation of header_v1 or header_v2:
header_base* make_header(unsigned int magic);

header_base.cpp:

#include "header_v1.h"
#include "header_v2.h"

header_base* make_header(unsigned int magic)
{
    switch(magic)
    {
       case Magic_V1: 
          return new header_v1;
       case Magic_V2: 
          return new header_v2;
       default:
          assert(0);
          return 0;
    }
}

然后在两个单独的地方实现

在 headerv1.h 中:

class header_v1 : public header_base
{
    int func1(char *stuff);
    ... 
};

header_v1.cpp:

#include "header1.h"

int header_v1::func1(char *stuff)
{
   ... 
   return 17;
}

header_v2.h 和 header_v2.cpp 也类似。

【讨论】:

  • 如果库不是仅标头,这不是一个特别好的主意,因为它会与损坏的名称混淆。见stackoverflow.com/a/6670753/46642
  • 正是我会做的。我也可能会声明一个包含标头声明的功能的 ABC,并有 2 个 ABC 的具体派生;每个版本一个。
  • 结构体只定义了数百种基本类型,没有函数。为了动态使用 header_base,我必须存储一个指向顶级结构的指针,然后为数百个结构成员中的每一个创建虚拟 getter,然后为每个派生包装类的每个成员实现 getter。跨度>
  • 听起来正确的做法是将差异化降低一到三个级别。或者,只需更改实际的头文件...
  • 好的,最后我将采用您的替代(第二个)想法...我创建了一个虚拟类作为标题的接口,我将存储 (void*) 引用到顶级结构,这样我就可以将所有内容编译成一个二进制文件,或者回退到动态加载包含实现类的库。
猜你喜欢
  • 2014-11-17
  • 1970-01-01
  • 1970-01-01
  • 2012-08-02
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 2018-06-07
相关资源
最近更新 更多