C++ C++;设计同一接口的多个版本(头文件中的枚举/结构)

C++ C++;设计同一接口的多个版本(头文件中的枚举/结构),c++,struct,interface,enums,C++,Struct,Interface,Enums,我们正在与一个外部控制的程序进行接口,该程序具有定义的包含枚举和结构的头。我们希望能够以尽可能少的代码重复与该程序的多个版本交互。每个版本都有相同的通用枚举和结构,但随着时间的推移会有轻微的修改。在理想的设置中,我们可以有条件地包括同一个报头的不同版本(即如果与版本1的接口连接包括“Vrime1 \ PrdFr.h””,否则“包含”Value2\PrdFr.h(),但不相信C++中是可能的。p> 下面是一个简单的例子来说明这个问题以及我们目前正在做的事情。谢谢你的帮助 版本1\progDefs.

我们正在与一个外部控制的程序进行接口,该程序具有定义的包含枚举和结构的头。我们希望能够以尽可能少的代码重复与该程序的多个版本交互。每个版本都有相同的通用枚举和结构,但随着时间的推移会有轻微的修改。在理想的设置中,我们可以有条件地包括同一个报头的不同版本(即如果与版本1的接口连接包括“Vrime1 \ PrdFr.h””,否则“包含”Value2\PrdFr.h(),但不相信C++中是可能的。p> 下面是一个简单的例子来说明这个问题以及我们目前正在做的事情。谢谢你的帮助

版本1\progDefs.h包含

enum items
{  
  BOOK_TYPE = 0,
  PAGE_TYPE = 1,
  WORD_TYPE = 2
};
struct packet
{
  int type;
};
enum items
{  
  VOLUME_TYPE = 0,
  BOOK_TYPE = 1,
  PAGE_TYPE = 2,
  WORD_TYPE = 3
};
struct packet
{
  int type;
  char detail[80];
};
版本2\progDefs.h包含

enum items
{  
  BOOK_TYPE = 0,
  PAGE_TYPE = 1,
  WORD_TYPE = 2
};
struct packet
{
  int type;
};
enum items
{  
  VOLUME_TYPE = 0,
  BOOK_TYPE = 1,
  PAGE_TYPE = 2,
  WORD_TYPE = 3
};
struct packet
{
  int type;
  char detail[80];
};
我们现在希望将数据包结构写入网络,以便能够在运行时选择使用哪个版本。目前我们有一个基类,然后每个版本有一个子类。它们看起来像这样

baseWriter.h

class baseWriter
{
    virtual void sendBookPacket() = 0;
};
version1Writer.cpp

#include "baseWriter.h"
#include "version1\progDefs.h"

class version1Writer : public baseWriter {};
void version1Writer::sendBookPacket()
{
  struct packet pkt;
  pkt.type = BOOK_TYPE;
  sendNetworkPacket((void*)&pkt, sizeof(pkt));
}
#include "baseWriter.h"
#include "version2\progDefs.h"

class version2Writer : public baseWriter {};
void version2Writer::sendBookPacket()
{
  struct packet pkt;
  pkt.type = BOOK_TYPE;
  sendNetworkPacket((void*)&pkt, sizeof(pkt));
}
version2Writer.cpp

#include "baseWriter.h"
#include "version1\progDefs.h"

class version1Writer : public baseWriter {};
void version1Writer::sendBookPacket()
{
  struct packet pkt;
  pkt.type = BOOK_TYPE;
  sendNetworkPacket((void*)&pkt, sizeof(pkt));
}
#include "baseWriter.h"
#include "version2\progDefs.h"

class version2Writer : public baseWriter {};
void version2Writer::sendBookPacket()
{
  struct packet pkt;
  pkt.type = BOOK_TYPE;
  sendNetworkPacket((void*)&pkt, sizeof(pkt));
}
这将起作用,但正如您所看到的,这两个类中的代码是完全相同的。唯一的区别在于使用的值和结构,因为标题的版本不同。实际上,这个项目有很多枚举,有数百个项和许多结构,我们都无法控制它们。它们可以随时更改,但我们的代码不需要更改,因为新元素与程序无关。但是,这些更改确实会影响所用元素的值/大小。有没有办法设计我们的代码来使用这些头而不复制代码?谢谢大家!


注意:我们不支持C++11。谢谢你的建议。许多建议都是我不熟悉的编码术语,需要测试以确定编译器是否支持这些术语,并将尝试逐一响应。

这似乎是一个很好的选择。visitor模式将允许您选择在运行时而不是编译时实例化哪个对象。

您可以将每个
progDefs.h
文件的内容包装到结构中,最好是直接,或者如果您无法修改它,可以这样:

struct Version1 {
#include "version1\progDefs.h"
};
然后,您可以将
baseWriter
设置为模板类:

template <typename Version>
class baseWriter
{
    using packet = typename Version::packet;
    using items = typename Version::items;

    void sendBookPacket() {
        packet pkt;
        pkt.type = items::BOOK_TYPE;
        sendNetworkPacket((void*)&pkt, sizeof(pkt));
    }
};

您也可以在没有这些typedef的情况下做任何事情,它们只是稍微简化了代码。

如果您想确保代码正常工作,我认为您需要像以前一样复制代码。您不必手动复制,您可以自动生成代码以节省工作和许多潜在的错误。

您可以修改
progDefs.h
内容吗?这是另一个程序的界面。因此,虽然我们可以物理地修改头文件,但这些值需要按照定义。即,为了与版本1接口,我们必须发送一个值为0的4字节数据包。对于版本2,我们必须发送一个84字节的数据包,前4个字节中的值为1。感谢您查看问题。条件包含在C++中是绝对可能的,但是在运行时不能选择。(这是C和C++有争议的特性之一)你能详细说明一下这个建议吗?游客的哪一面,哪种颜色?谢谢你的邀请reply@talisman:如果我们使用链接中的示例,BaseWriter将成为颜色基类,version1Writer和version2Writer将分别成为红色和蓝色类。那么访问者将是sendBookPacket函数的访问者?但在提供的示例中,countVisitor只包含红色和蓝色的变量。我们可以使用名称空间在访问者中包含两个版本的头,但无法看到这将如何避免代码重复,因为我们必须实例化和引用所有版本的结构和枚举。您可以让访问者函数执行不同的操作,然后在基类中调用公共函数。很抱歉,但我无法想象答案。如上所述,整个功能是通用的。问题是它需要引用一个结构类型和枚举值,该值具有多个定义,具体取决于您使用的标题。如果有一个代码片段可以用上面的例子来处理,我们将不胜感激。我们考虑使用宏来自动生成每个子类的代码,但不是首选的方法。感谢您的回复。这个案例“使用”的是C++11的一个新特性吗?我只熟悉名称空间。编译器不喜欢这种语法。谢谢。@talisman:是的,这是C++11的新功能。如果您使用的是较旧的编译器,请使用进行更改typedef@talisman是的,您可以使用@MantoshKumar所说的
typedef
,查看我的更新。谢谢!我花了一点时间来编译它,因为我通常不在结构中使用模板或枚举,但这个解决方案确实有效。注意:当更改为typedef时,方法必须将items::BOOK_TYPE设置为Version::BOOK_TYPE。不确定这是否也是C++11的错误,或者只是更改为typedef的症状。再次感谢您-将必须确定这是否对更大的项目有意义。从未将模板与继承混合使用。@talisman很高兴它起到了作用。关于
items::BOOK_TYPE
vs
Version::BOOK_TYPE
——这也是C++11中的一项功能,您可以使用枚举名称进行范围解析,即使对于旧式枚举也是如此。抱歉搞混了。