0

このような datacontainertype がいくつかありますが、内容が異なります。

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++ で Templates を使用すると、テンプレートのタイプを指定する必要があります。

コレクションの型を特定する必要なく、派生クラスで X と Y を定義するにはどうすればよいですか?

4

4 に答える 4

1

(実行時の)ポリモーフィズムが必要なように聞こえます。つまり、IMyInterface正確なタイプを知らなくても処理するコードが必要です。テンプレートだけでは、コンパイル時のポリモーフィズムしか提供されないため、そこに到達することはできません。必要なものを提供するC++の部分は、RTTI(実行時型情報)と仮想関数です。C ++の非常に強力な機能の1つは、2つのアプローチを組み合わせることができることです。あなたの場合、それはテンプレートに変わることを意味します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_ptrC ++ 11を使用している場合)は良い選択です。またboost::any、任意のタイプのオブジェクトを安全な方法でラップする(つまり、正しく実行される)を確認することもvoid*できます。

ところで、あなたの使用はunion少し疑わしいです。DoThingsデータにリクエストまたはレスポンスが含まれているかどうかをメソッドはどのように知るのでしょうか?boost::variantCスタイルのユニオンの代わりに使用することを検討することをお勧めします。

于 2012-10-05T13:03:27.163 に答える
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 に答える
0

これを回避するには、いくつかのオプションがあります。

  1. アドレスを保存しているので、その引数を void *:

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

  2. テンプレートIMyInterfaceなしでインターフェースを継承させます。

  3. 考慮したい組み合わせがいくつかあり、共通点がない場合は、それをオーバーロードできます。
于 2012-10-05T12:59:37.670 に答える
0

できません。STL コレクションは、挿入された要素のサイズを知る必要があり、それを決定するには完全な型指定が必要です。

于 2012-10-05T12:22:38.810 に答える