2017-04-19 4 views
2

は、これらの定義および説明の目的のために、これらの線に沿っていくつかのコードを考える:基本となる型を知らなくても、テンプレート化された親クラスから値を戻すにはどうすればよいですか?

class Child 
{ 
    private: 
    std::string name; 

    public: 
    Child(const std::string & name) name(name) 
    { } 
} 

template<typename T> 
class Parent : public Child 
{ 
    private: 
    T data; 

    public Parent(const std::string & name, const T & data) : Child(name), data(data) 
    { } 

    inline GetData() const 
    { 
     return this->data; 
    } 
} 

std::vector<std::unique_ptr<Child>> values; 
values.emplace_back(std::make_unique<Parent<int>>("value a", 4)); 
values.emplace_back(std::make_unique<Parent<std::string>>("value b", "test")); 

for (const auto & v : values) 
{ 
    // I want to access the int and string here! 
} 

どのように私はここに、基本クラスから親クラスで使用されるタイプを決定するのでしょうか?

私が働いている具体的なシナリオでは、私はSQLのストアドプロシージャのパラメータとstd::vector<std::unique_ptr<SqlParameterBase>>に含まれることになってと表すクラスに渡されSqlParameter<T>テンプレートについての情報を含むSqlParameterBaseクラスの束を持っていることを、実際にありますストアドプロシージャの設定を呼び出すことができます。

しかし基本的な問題は、基になるデータにアクセスする必要があり、データへのポインタを格納するために基本クラスにvoid *を定義することを避けたかったということです。私はそれが可能な限り型の安全であることを好むでしょう。

私はこの問題を解決するための代替設計やアプローチにもオープンしています。より良いと感じたら、全く別のものを提案してください。

+0

あなたは本当に欲しいのはバリアント型です。 – juanchopanza

+0

ええ、私は親の型への動的キャストを行う必要があることを知っています。つまり、すべてのタイプをハードコードされた方法でテストすることなく、どのタイプをキャストするかを判断することはできません。結局、私は基本的に、ベクトルの要素の数や文字列の長さなど、データのサイズを決めることができる必要があります。それらのメンバ関数は型に基づいて変更されます。私はテンプレートについて考えて、T :: sizeが存在すると仮定しただけですが、関数の動作が型間で異なって定義されていると危険です。 –

+0

データの「サイズ」を決定する必要がある場合、 'virtual std :: size_t size()const = 0;'を 'Child'に追加する方法はありますか? – aschepler

答えて

0

派生型にのみ存在する子の約束機能(型付きデータを返す)が必要です。継承の下では、これは抽象的な機能です。したがって、一連の投機的な仮想アクセッサです。アップキャストは実際にここでは必要ありません。

私は言うでしょう。子が返すものを約束することを望まない場合は、何かを返します。あなたのインターフェースが広すぎると思われます。代わりに、投機的なキャストなどを使ってインターフェースを消費するコードにインターフェースを入れています。

Childのセットは、Childで定義されたインターフェースを介してインターフェースできますか、またはDerivedでしか使用できない特別な機能を持ち、そのように話されなければなりません。

追加情報として、コンテナ内のタイプ情報を完全に訂正する代わりに、std::vector<std::variant<type1, type2, ...>>と考えることがありますか? std :: variantはC++ 17 ofcなので、適切ではないかもしれませんが、サードパーティの実装があります - バリエーションの変更など

+0

あなたは抽象的な機能を説明し、それは私に思い出させました。親クラスに 'virtual size_t GetSize()= 0'を設定し、それをサポートされているバッキングデータに特化した多くの子クラスに実装するのが適切な設計ですか?例えば、私は 'StringChild'と' IntChild'を持っていて、それぞれはデータとデータのサイズを取得する独自の方法を実装します。私はループ内を切り替えて、列挙型を使用してデータ型を追跡し、データを取得する必要があるときに動的にキャストします。コードがたくさんあるようですが、インターフェースがはるかに狭くなります。 –

+0

いくつかの読書と混乱の後、 'std :: variant'は実際に私のニーズに合っています。私は、各SQL型のサポートされている型のセットと、クエリのパラメータの予想されるSQL型に基づいてサポートされている少数のデータ型の単なる*試行*変換に自分の機能を減らしました。 –

0

(質問のために:は、どのように私はここに、基本クラスから親クラスで使用されるタイプを決定するであろう?):このプログラムを試してみてください

出力タイプを印刷します。.. しかし、いくつかのより多くの仕事がありますよりよく見えるようにする必要がある

value a of type:i 
value b of type:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 

ここで "i"は最初の行の整数を意味します。

2番目の文字列には "basic_string"が含まれています。しかし、その周りのいくつかの迷惑。

より良いアイデアを引き起こす可能性があるので、私はこれを投稿しています。

修正されたコードのコメントが追加されました。

関連する問題