3

私が経験しているエラーを取得する代表的なコードを次に示します。

class Data
{
};

class Table
{
  virtual std::vector<Data*> getData() = 0;
  virtual void putData(Data* dataItem) = 0;
  virtual Data* getData(int index) = 0;
};

class DerivedData : Data
{
};

class DerivedTable : Table
{
  std::vector<DerivedData*> getData() { return myData; } // invalid covariant return type
  void putData(DerivedData *dataItem) { myData.push_back(dataItem); }
  virtual DerivedData* getData(int index) { return myData[index]; } // invalid covariant return type

  std::vector<DerivedData*> myData;
};

まず、putData のオーバーライドがパラメーターの変更に満足している理由がよくわかりませんが、getData の戻り値の型を変更することはできません。読む。

次に、私の主な質問ですが、このコードを変更して機能させるにはどうすればよいでしょうか。私の基本的な目標は、データ オブジェクトを格納および制御する複数の「テーブル」のようなオブジェクトを許可することです。各データ オブジェクトにはいくつかの共通点がありますが、テーブルが制御および操作するいくつかの明確な違いがあります。たとえば、1 つのテーブルに name パラメータを持つデータ オブジェクトがある場合、そのテーブルは保持するデータのすべての名前のリストを出力する関数を提供します。このようにして、これらすべてのテーブル オブジェクトで動作する汎用コードと、1 種類のテーブルのみで動作する特殊なコードを作成できます。

4

2 に答える 2

5

多くのことが間違っています:

  1. の 2 つのバージョンはputData、単に異なる、無関係なオーバーロードです。C++ で仮想関数をオーバーライドするための「反変の引数型」などというものはありません (仮にあったとしても、その逆になります!!)。キーワードoverrideを派生関数に追加して、コンパイラがエラーを生成するようにします。

  2. クラス テンプレートは、あなたが思うようには機能しません。template <typename T> class Fooがクラス テンプレートである場合、 と が何らかの形で関連しているかどうかに関係なく、Foo<X>Foo<Y>まったく異なる、無関係なクラスです。XY


std::vector<std::unique_ptr<Data>>@Beta が言うように、メインのデータ構造として単純なものがあるだけかもしれません。とにかく、本当に何らかの階層が必要な場合は、可能な「解決策」を次に示します。

#include <memory>
#include <vector>

struct Data { virtual ~Data() { } };

struct Table
{
    virtual ~Table() { }

    typedef std::unique_ptr<Data> data_ptr;
    typedef std::vector<data_ptr> dataset_type;

    virtual dataset_type & getData() = 0;
    virtual void putData(data_ptr dp) = 0;
    virtual Data & getData(std::size_t n) = 0;
};

class DerivedTable : public Table
{
    dataset_type myData;

public:

    virtual void putData(data_ptr p) override
    {
        myData.push_back(std::move(p));
    }

    Data & getData(std::size_t n) override
    {
        return *myData[n];
    }

    // ...
};
于 2012-11-05T13:15:21.650 に答える
1

「無効な共変の戻り値の型」は、実際には の戻り値の型を変更しようとしたことが原因ですgetData()。戻り値の型は関数識別子の一部ではありませんが、それでもいくつかの制限があります。一部の基本クラスをオーバーライドするメソッドは、同様に動作する必要があります。つまり、仮想メソッドの実装は、 (not )の観点からData呼び出すクライアントの有効なポインターを返すために、にアップキャストを実行しようとします。これはfrom context ofと比較できます。getData()Table*DerviedTable*(Data*)myData[index]DerviedTable::getData(int)

それは、コンパイラが混乱する正確な場所です。

class DerivedData : Data
{
};

この宣言は、 がprivatelyDervidedDataを継承することを示しています。つまり、 のクライアントは、それが実際に であることを「認識」していません。からアップキャスト にアクセスできないため、コードの生成も不可能になります。Data DerviedDataDataDerviedData* getData() overrideDataDeviedTable::getData(int)

そのエラーを解消するには、継承をパブリックに表示することができます。

class DerivedData : public Data
{
};

または友達を作る

class DerivedData : Data
{
    friend class DerivedTable;
};

このデザインはまだ質問の対象ですが。

于 2016-05-12T20:09:29.953 に答える