2012-01-09 9 views
0

ベクトルに親*オブジェクトの束を格納できることはわかっています。ただし、オブジェクトを呼び出す必要がある関数を親クラスで定義できない場合(サブクラスのテンプレートパラメータに依存します)、コンテナからオブジェクトをどのように取得する必要がありますか?この例ではベクトルから派生クラスオブジェクトを取得する<Parent*>

#include <iostream> 

class ImageBase{}; 

template <typename TPixel> 
class Image : public ImageBase 
{ 
public: 
    TPixel GetPixel() const {TPixel a; return a;} 
}; 

template<typename TImage> 
void Output(const TImage* image) 
{ 
    std::cout << image->GetPixel(); 
} 

int main(int, char *[]) 
{ 
    // Works correctly 
    { 
    Image<float>* image = new Image<float>; 
    image->GetPixel(); 
    Output(image); 
    } 

    { 
    ImageBase* image = new Image<float>; 
    Output(image); 
    } 

    return 0; 
} 

出力(画像)。ここで、 'image'はImageBase *であり、GetPixelはImageBaseで定義されていないため失敗します。 dynamic_cast <>サブクラスがいずれかのサブクラスと一致するかどうかを調べるには、たくさんのタイプに分かれていますが、このリストは非常に迅速に長くなる可能性があります。長いリストは1つの場所に置くことができればうまくいくだろうが、これを行うにはどうすればよいだろうか?この関数はImageBase *を取りますが、それは何を返しますか?

returnType? GetSubclass(ImageBase* input) 
{ 
    if(dynamic_cast<Image<float>*>(input)) 
    { 
    return Image<float>*; 
    } 
    else if(dynamic_cast<Image<int>*>(input)) 
    { 
    return Image<int>*; 
    } 
} 

それだけで(この例では、セットアップなど)そのテンプレートパラメータによって署名が異なるサブクラスにいくつかのテンプレート関数を呼び出すことができるようにしたいために私には合理的なようで、それをしないのですか?

私の実際のケースでは、ImageとImageBaseの両方がライブラリの一部であるため、それらを変更することはできません。

+1

訪問者のデザインパターンをチェックすると、ダブルディスパッチを実装できます。 – P3trus

+0

おそらく 'any_cast'関数としてBoost.anyを試してみてください。 –

+0

Kerrek SB - any_castの場合、すでにタイプを知る必要がありますか? std :: vector v; v.push_back(新しいint); int * any_cast (v [0]); –

答えて

3

visit機能を実装したテンプレートヘルパーを使用して、型情報を回復する訪問者パターン。

まずは、多型関手オブジェクトにあなたのアルゴリズムを作成してみましょう:

struct Output 
{ 
    std::ostream& dest; 
    Output(std::ostream& destination) : dest(destination) {} 

    template<typename PixelType> 
    void operator()(const Image<PixelType>* image) const 
    { 
     dest << image->GetPixel(); 
    } 
}; 

それでは、ビジター・インターフェースを追加してみましょう:

struct ImageVisitor /* abstract */ 
{ 
    virtual void Visit(Image<RGBQUAD>*) const = 0; 
    virtual void Visit(Image<RGBTRIPLE>*) const = 0; 
    virtual void Visit(Image<RGBQUAD16>*) const = 0; 
    virtual void Visit(Image<RGBTRIPLE16>*) const = 0; 
    virtual void Visit(Image<RGBQUADF>*) const = 0; 
    virtual void Visit(Image<RGBTRIPLEF>*) const = 0; 
    virtual void Visit(Image<RGBQUADD>*) const = 0; 
    virtual void Visit(Image<RGBTRIPLED>*) const = 0; 
}; 

そしてフォワーダ:

template<typename Functor> 
struct ImageVisitorShim : ImageVisitor 
{ 
    Functor& fn; 
    ImageVisitorShim(Functor& algorithm) : fn(algorithm) {} 

    virtual void Visit(Image<RGBQUAD>  *im) const { fn(im); } 
    virtual void Visit(Image<RGBTRIPLE> *im) const { fn(im); } 
    virtual void Visit(Image<RGBQUAD16> *im) const { fn(im); } 
    virtual void Visit(Image<RGBTRIPLE16> *im) const { fn(im); } 
    virtual void Visit(Image<RGBQUADF> *im) const { fn(im); } 
    virtual void Visit(Image<RGBTRIPLEF> *im) const { fn(im); } 
    virtual void Visit(Image<RGBQUADD> *im) const { fn(im); } 
    virtual void Visit(Image<RGBTRIPLED> *im) const { fn(im); } 
}; 

そして、工場:

0今

訪問者に準拠した画像のラッパー:

struct VisitableImageBase 
{ 
    virtual void VisitWith(const ImageVisitor&) = 0; 
}; 

template<typename PixelType> 
struct VisitableImage : VisitableImageBase 
{ 
    unique_ptr<Image<PixelType>> content; // or shared or raw pointer, if ownership is elsewhere 

    VisitableImage(Image<PixelType>* im) : content(im) {} 

    virtual void VisitWith(const ImageVisitor& v) { v.Visit(content.get()); } 
}; 

は最後に、あなたは、画像の多型のベクターを使用することができます!

多くのコードでしたが、良いものは限りファンクタをテンプレートで実装されたように(ちょうどシムを拡張)新しいタイプは、既存のファンクタに影響を与えずに追加することができるということである。
vector<unique_ptr<VisitableImageBase>> images; 
Output outputter(std::cout); 
for(auto vim : images) vim->VisitWith(MakeImageVisitor(outputter)); 

さらに、画像処理関数を追加するコードはあまり必要ありません(Outputに似た新しいテンプレートファンクタクラス)。

+0

私はVisitorパターンを認識していますが、ここでどのように適用されるかわかりません。私はコンテナ内のすべてのアイテムに対して操作を実行するというコンテキストでそれを見てきましたが、この場合、その操作を実行するのは問題が発生している場所です。これらのオブジェクトで呼びたいすべての機能でビジターを使用する必要がありますか? –

+0

@DavidDoria:OK、例が完了しました(しかし、テストされていません)。 –

+0

Ben Voigt - うわー、それはたくさんのコードです。この例をありがとう!しかし、私にはFunfactorsになるのは非常に面倒な機能テンプレートがたくさんあります。なぜこれがとても複雑であるのか、私はまだ分かりません。サブクラスオブジェクトは、その型を正しく「知っています」 - 元の型に戻すことができる関数がない理由はわかりません。 ( 'new'によって作成されました) –

関連する問題