0

我有几个这样的数据容器类型,但它们的内容不同:

struct containerRequest
{
   uint8_t data1
   uint8_t data2
};

struct containerResponse
{
    uint8_t data1;
    uint8_t data2;
};

union myType
{
   containerRequest Request;
   containerResponse Response;
};

现在我想创建一个抽象接口以确保所有这些接口都具有这样的 MyDatatype

class IMyInterface
{
   public: 
      union myType
      {
          X Request;
          Y Response;
      };


      bool IsMyType(myType& data) = 0;
      void DoThings(myType& data) = 0;
};

我想过使用模板,但这会破坏我的其余代码:

template <typename X, typename Y>
class IMyInterface
{
    ...
}

但这破坏了我的其余代码。

因为我收集了不同的容器:

void addContainer(IMyInterface& data)
{
     collection.push_back(&data);
}

当我在界面中使用模板时,g++ 会强制我指定模板的类型。

如何在我的派生类中定义 X 和 Y 而无需在我的集合中指定类型?

4

4 回答 4

1

如果您不需要任何方法,我会继续使用结构,如果您这样做,我会使用这样的方法:

enum PacketType {Request,Response};

// General interface defining which methods must they both provide
class Packet {
    virtual PacketType GetType() = 0;

    ...
}

// As many Packet subtypes as you need
class Response : Packet {
    virtual PacketType GetType(){
        return Response;
    }
}

class Request : Packet {
    virtual PacketType GetType(){
        return Request;
    }
}

// And use it in (e.g.) vector:
std::vector<Packet *> collection;
collection.push( new Request());
collection.push( new Response());
于 2012-10-05T12:24:54.563 回答
1

听起来您需要(运行时)多态性,即想要在IMyInterface不知道其精确类型的情况下处理 an 的代码。单独的模板不会让你到达那里,因为它们只提供编译时多态性。提供您想要的 C++ 部分是 RTTI(运行时类型信息)和虚函数。C++ 极其强大的特性之一是您可以将这两种方法结合起来。在您的情况下,这意味着IMyInterface变成模板,但让该模板继承自定义您需要的虚函数的非模板基类。这是一个例子。

// Base class for interface types. Make sure it's a polymorphic type by adding a least one
// virtual member. Since polymorphich types should have virtual destructory anyway, adding
// a virtual no-op destructor is the natural choice.
struct IMyInterfaceDataType {
  virtual ~IMyInterfaceDataType() {};
};

// Base class for interface implementations.
struct IMyInterface {
  virtual bool IsMyType(const IMyInterfaceDataType& data);
  virtual void DoThings(IMyInterfaceDataType& data);
}

template<typename RequestType, typename ResponseType>
struct IMyInterfaceImplementation : MyInterface {
  struct MyType : IMyInterfaceDataType {
    union { RequestType Request; ResponseType Response } data;

    // You'll probably want to add some constructors here
  };

  virtual bool IsMyType(const IMyInterfaceDataType& data) {
    // Cast as pointer, not reference, to get NULL instead of an exception if cast fails
    return dynamic_cast<const MyType*>(&data) != NULL;
  }
};

struct SomeRequestType { ... };
struct SomeResponseType { ... };
struct SomeInterface : IMyInterfaceImplementation<SomeRequestType, SomeResponseType> {
  virtual void DoThings(IMyInterfaceDataType& data_raw) {
    // Throws std::bad_cast if data_raw isn't actually a DataType instance
    DataType& data = dynamic_cast<DataType&>(data_row);
    ... Do whatever you want to do with data ...
  } 
};

// This should now work, but you need to store pointers (or references, but
// putting references into a std::vector doesn't work), since polymorphism only
// works as expected with references or pointers.
std::vector<IMyInterface*> interfaces;
void addCollection(IMyInterface* iface) {
  interfaces.push_back(iface);
}

// This would then process an arbitrary data type with the first matching interface
void process(IMyInterfaceDataType& data) {
  for(std::vector<IMyInterface>::iterator i = interfaces.begin(); i != interfaces.end(); ++i) {
    IMyInterface& iface = **i;
    if (iface.IsMyType(data) {
      iface.DoThings(data);
      break;
    }
  }
}

在实际代码中,您当然应该在向量中存储原始点interfaces,而是使用某种智能指针。boost::shared_ptr(或者std::shared_ptr如果您使用的是 C++11)将是一个不错的选择。您可能还想看看boost::any,它以安全的方式包装了任意类型的对象(即,在某种程度上,它void*是正确的)。

顺便说一句,您的使用union有点可疑。方法如何DoThings知道数据是包含请求还是响应?您可能要考虑使用boost::variant而不是 C 风格的联合。

于 2012-10-05T13:03:27.163 回答
0

你不能,STL 集合需要知道插入元素的大小,并且需要完整的类型规范来确定它。

于 2012-10-05T12:22:38.810 回答
0

有几个选项可以解决这个问题:

  1. 由于您要存储其地址,因此将其参数设为 void *:

    void addContainer(void * data) { collection.push_back(data); }

  2. 使IMyInterface继承没有模板的接口。

  3. 如果你有几个你想考虑的组合并且没有共同点,你可以重载它。
于 2012-10-05T12:59:37.670 回答