1

C++ で型消去パターンを使用しました。つまり、テンプレート クラスを抽象クラスで非表示にしました。

class Base{

  virtual ~Base(){}

 //pure virtual methods...
};

template<typename T>
class Derived : Base{

Derived<T>(){}
~Derived(){}

//public methods...

private :
vector<T> datas;

};

問題 : データを取得または変更する場合は、Base クラスを使用する必要があります

アクセサ getDatas() および SetDatas(vector datas) を定義するにはどうすればよいですか?

4

4 に答える 4

1

あなたは型消去を実装しようとしていて、消去している型でクライアントを操作させる方法を尋ねています。ここでデプロイするパターンは、派生クラスにBase、格納されている具体的なタイプのデータを参照せずに呼び出すことができる共通の操作がある場合にのみ適切です。そのような一般的な操作がなく、クライアントがBaseインターフェイスを介して行う意味的に有用なことは、派生クラスの具象型を使用することだけである場合、この設計を使用することはできません。

于 2010-08-27T15:12:05.713 に答える
1

型消去は、派生クラスがテンプレートから生成される(実行時)ポリモーフィズムの形式です。

ポリモーフィズムのすべての形式と同様に、派生クラスには、構文的に基本クラスで表現できる共通点が必要です。

編集:

OK、stijnの答えは私にアイデアを与えました。私はまだ既製品 ( boost::any) を使用する必要があると考えていますが、キックのために、ここにスケッチがあります。

class Base
{
public:
  template< class T >
  bool SetData(const std::vector<T>& data)
  {
    return SetData(&data,typeid(T));
  }
private:
  virtual bool SetData(const void* data, const std::type_info& tid) = 0;
}

template< class T >
class Derived : public Base
{
public:
  bool DoSetData(const std::vector<T>& data)
  {
    // tbd
  }
private:
  virtual bool SetData(const void* data, const std::typeinfo& tid)
  {
    if( tid != typeid(T) )
      return false;
    const std::vector<T>* pdata = reinterpret_cast<const std::vector<T>*>(data);
    return DoSetData(*pdata);
  }
}

何て言う?

于 2010-08-27T15:04:30.700 に答える
1

std::vector には型が必要なため、SetData( vector ) を定義することはできません。また、T の定義がない場合、Base で SetData( std::vector< T > ) を定義することは明らかにできません。

したがって、これが本当に必要であり、これが進むべき道だと思う場合は、型のディスパッチを調べる必要があります (または void* を使用してハックする必要があります)。Boost は、いくつかの場所でタイプ ディスパッチを使用します。それ以外の場合は、Google が例を提供します。

それがどのように見えるかの簡単な例を編集します。ディスパッチをタイプするわけではありませんが、より簡単です

class Base
{
public:
  template< class T >
  bool SetData( const std::vector< T >& t )
  {
    return SetData( static_cast< const void* >( &t ), typeid( t ) );
  }

protected:
  virtual bool SetData( const void*, const std::type_info& ) = 0;
};

template< class T >
class Derived : public Base
{
protected:
  bool SetData( const void* p, const std::type_info& info )
  {
    if( info == typeid( std::vector< T > ) )
    {
      const std::vector< T >& v = *static_cast< const std::vector< T >* >( p );
      //ok same type, this should work
      //do something with data here
      return true;
    }
    else
    {
      //not good, different types
      return false;
    }
  }
};
于 2010-08-27T14:57:54.177 に答える
0

最終的に、クラスのユーザーは、基本型を介してアクセスしている場合でも、派生型のデータを操作するために T が何であるかを知っている必要があります。

void* を使用してある程度一般的なインターフェイスを設定できる場合がありますが、クラスのユーザーは、各クラスのインスタンスを特定の型 T に一致させる必要があります。T が int の場合、ユーザーはそれを知る必要があります。コレクションはintに基づいています。

どのインスタンスがどの型であるかを気にせずに任意の型をベクターに格納したい場合は、T を void* にすることができます。これを行うとtemplate<typename T>、派生の部分をスキップすることさえできます。非テンプレート クラスになる可能性があります。

于 2010-08-27T15:01:10.083 に答える