0

これが私が達成しようとしていることです:

さまざまなタイプのリンクリストを作成しようとしています。これを実現するには、ポリモーフィズムが最適な方法であると考えました。

AttributeBase と Attribute の 2 つのクラスがあります。AttributeBase は AttributeSet によって使用されます。これは、Attribute<T> のリンクされたリストの開始点と終了点を (AttributeBase* として) 格納し、リストを変更します。AttributeBase は Attribute<T> の基本クラスであり、ジェネリック ポインターを作成するためだけに設計されています。もちろん、Attribute<T> は、実際の値が格納される AttributeBase の特定の型です。各 Attribute<T> の主なデータは、継承された文字列 (属性の名前、または必要に応じて「キー」) と型 T の値です。

だから、これまでのところ私は(簡略化):

class AttributeBase
{
  public:
    AttributeBase() = delete;
    AttributeBase* GetNext() { return next; };
    AttributeBase* GetPrev() { return prev; };
    std::string GetName() { return name; };
    //Sometimes I need to get/set the value stored in a derived class
    //But, how would I define the function here since the return
    //type is of type T as defined in Attribute?
    virtual ???? GetValue = 0;
    virtual void SetValue(????) = 0;

    friend class AttributeSet;
  private:
    AttributeBase* next = nullptr;
    AttributeBase* prev = nullptr;
    std::string name;
};

template <class T>
class Attribute : public AttributeBase
{
  public:
    Attribute( std::string _name, T _value ){ name = _name; value = _value };
    T GetValue(){ return value; };
    void Setvalue(T){ value = T; };
  private:
    T value;
};

class AttributeSet
{
  public:
    template <class T>
    void Add(std::string,T); //Add an Attribute<T>(std::string,T) to the list
    void Delete(std::string);
    bool Contains(std::string _name); //Scan the list to determine if an
                                      //attribute with name of _name exists
    template <class T>
    T Get(std::string); //Scan the list for 'name' and return
                        //AttributeBase*->GetValue()
  private:
    AttributeBase* start = nullptr;
    AttributeBase* end = nullptr;
}

AttributeBase を一般的で非テンプレート化したままにしようとしたため (AttributeSet で厳密に型指定された開始ポインターと終了ポインターを回避するため)、これにより問題が発生します。仮想関数 BaseAttribute::GetValue() の現在のところ未指定の戻り値の型を指定するにはどうすればよいですか。最初に を使用してみautoましたが、コンパイル エラーが発生しました。

AttributeBase のインスタンスが実際に作成されない (そしてデフォルトのコンストラクターが削除される) ため、GetValue を省略して派生クラスで定義することが可能であると考えました。ただし、 *AttributeBase->GetValue() を試してみると、 GetValue() が AttributeBase で定義されておらず、サブクラスのみで定義されているため、エラーが発生します。AttributeBase は直接構築できないため、ポインターが派生クラス (唯一の派生型) を指す必要があることをコンパイラーが認識していると思われるでしょう。

したがって、GetValue() を使用するには、AttributeBase* を Attribute* にキャストできるように、前の値の型を事前に知っておく必要があります。AttributeBase 自体がテンプレート化され、値 T 型が含まれている場合、これは簡単です。次に、AttributeBase*->type にアクセスして、キャストする必要があるポインターの型を決定します。ただし、前述したように、AttributeBase をテンプレート化すると、オブジェクトの意図された使用が破棄されます。

おそらく、私はこれについて完全に間違った方法で行っています (またしても)。しかし、この時点で私はアイデアに行き詰まっています。どんな助けでも大歓迎です!

4

2 に答える 2

1

したがって、真に一般的な解決策は存在しません。基本クラスの仮想関数のオーバーライドはすべて同じ戻り値の型を持つ必要があるため、基本クラスから任意の型を取得することはできません。

これにより、2 つのオプションが残ります。

まず、共通の基本型から派生した任意のオブジェクトをリストに保持することを事前に決定できます。これにより、リストに入れることができるものが大幅に制限されますが、少なくともそれらのオブジェクトがそこにあると、それらを完全に自由に扱うことができます.

次に、オブジェクトがリストに追加された後に実際に何をしたいかによって、新しいBoost.TypeErasureライブラリを調べることができます。リストで行う必要があるのが、たとえば、それらすべてを出力すること、または少量の操作をいくつか出力することだけである場合、これはそこに到達するのに役立ちます。

于 2013-10-31T21:36:51.293 に答える
1

とのシグネチャは型GetValueSetValue依存するため、テンプレートである必要があります。ただし、クラス テンプレートを必要とせずに、テンプレート メンバーにすることができます。

class AttributeBase
{
  public:
    template <typename T> T GetValue() const;
    template <typename T> void SetValue(T);
//...
};

template <typename T>
T AttributeBase::GetValue() const
{
    return dynamic_cast<Attribute<T>&>(*this).GetValue();
}

template <typename T>
void AttributeBase::SetValue(T val)
{
    dynamic_cast<Attribute<T>&>(*this).SetValue(val);
}

template <typename T>
T AttributeSet::Get(std::string const& name) const
{
    // (assuming a private helper method Find().)
    const AttributeBase* attr = Find(name);
    if ( !attr )
        throw std::invalid_argument("attribute not in set");
    return attr->GetValue<T>();
}

ただし、間違った型を使用すると、これらの関数はすべて例外をスローします。AndSetValueは、そのテンプレート引数を自動的に推測する可能性があり、間違って推測する可能性があります。たとえば、が実際にaは である参照である場合、は と同じであり、スローされます。正しい式は(orですが、明示的なテンプレート引数の方が好みです)。AttributeBase&Attribute<long int>a.SetValue(1)a.SetValue<int>(1)a.SetValue<long int>(1)a.SetValue(1L)

于 2013-10-31T23:49:27.660 に答える