2012-05-07 22 views
4

私はpointAccumulatorのための抽象基底クラスを持っています。この抽象基底には、すべての点の平均を返す関数などのメソッドがあります。この2つのクラスの例を以下に示します。仮想関数とテンプレートの衝突

class lala { 
public: 
    virtual someFunctions = 0; 

    virtual bool isEmpty() = 0; 
}; 


class lalaLower : public lala { 
public: 
    lalaLower(){} 
    ~lalaLower(){} 


    someFunctions 

    template<class Archive> void serialize(Archive & ar, const unsigned int version) { 
     ar & heights_; 
    } 

protected: 
    std::deque<double> heights_; 
}; 

私はまた、これらのタイプを保存するには、ブーストのシリアル化を使用したいコードに見ることができるように。今、工場出荷時のパターンを使用して私はあなたがこのようなpointAccumulatorタイプを呼び出すと信じている:

lala *a1 = new lalaLower(); 

私の問題は、私はこのようにそれを呼び出す場合テンプレートSerializeメソッドはアクセスできないということです。また、C++ではこれが許可されていないので、抽象クラスのテンプレートクラスを持つことはできません。これを回避する方法はありますか?

編集:

私は直列化のための非侵入方法と考えられてきたが、それは理想的ではありませんどの公共するheights_を必要とし、またそれは良いプログラミングスタイルです。私は潜在的に、基本クラスを抽象的に保ちながら、フレンドクラスまたは関数を使用するメソッドが変数へのアクセスを持つクラスに浸透する可能性があると考えましたか?誰でもこれがどのように機能するのか説明できますか?

+4

これは基本的な問題です。仮想関数は、型に基づいた実行時選択に関するものです。テンプレートは、型に基づいたコードのコンパイル時生成に関するものです。実行時まで型を知らなければ、コンパイル時にコードを生成することはできません。 –

+0

うん、私は質問でそれを述べた。だから私は今質問があると思う、それについてもっと良い方法と別の方法があるのだろうか? –

+0

私はこれが書籍 "Modern C++ Design by Andrei Alexandrescu"で議論されている基本的なトピックだと思います。 これをよく理解したい場合は、それをお読みください。 – manasij7479

答えて

2

私は友人のクラスや関数を使用すると、良い解決策である、あなたはSerializor

のように新しいクラスを追加することができ、ここで

class Serializor; 
class meanAccumulator : public pointAccumulator 
{ 
public:  
meanAccumulator(){}  
~meanAccumulator(){}  
double getHeight();  
void addHeight(double Height);  
void setHeight(double Height);  
bool isEmpty(){ return heights_.empty(); }  

protected:  std::deque<double> heights_; 
friend int Serializor::Func1(Serializor&); 

}; 

が実際にhttp://msdn.microsoft.com/en-us/library/ahhw8bzz.aspx

1

Archive型のパラメータを多態性の階層にこの方法または別の方法でラップしないとできないと思います。

Boost.Serializationdoes it for youと思われます。

+1

+1 Boostがこの問題について既に考えて解決していなかったら、それは非常に意外でした! –

+0

私はこの解決策について少し混乱しています。多態的なメソッドを使用すると、テンプレートの必要性がなくなります。ただし、demo_polymorphic_A.cppと関連するhファイルの例では、クラスA(つまり、直列化されるクラス)です。とにかくテンプレート直列化を使用しますか?編集:私はそれを得る、テンプレートはまだありますが、彼らは明示的にインスタンス化するためにcppファイルを使用します。質問として、私は私の問題を解決するためにこれを使用することはできません私はまだこのソリューションを使用する抽象クラスでテンプレート関数が必要ですか? –

+0

私は実際には例が実際に壊れていると思います。 –

1

templatevirtualの方法が混同しないことをご存じでしょうか。

meanAccumulator::serialize()メソッドを削除し、class pointAccumulator本文に追加し、必要な場所にvirtual関数を呼び出すことをお勧めします。
派生クラスのハンドルを渡して、それを使ってメソッドを呼び出すことも考えられます。

class pointAccumulator { 
public: 
    template<class Archive, class Derived> 
    void serialize(Archive & ar, const unsigned int version, Derived &derived) 
    {           // optional ^^^^^^^^^^^^^^^^^ 
    // call virtual methods to derived from here 
    // optional: for non-virtual method, you can use derived class handle 
    } 
}; 

あなたが世話をする必要がある唯一の事は何でも非仮想メソッドあなたがderivedハンドルを使用してserialize()内部で呼び出す、ということである - >関わらず、何の、pointAccumulatorからすべての子クラスに同じ名前である必要があります彼らは内部で行う。

+0

私はclass pointAccumulatorを純粋に仮想的に保つことを望んでいたので、工場パターンは引き続き動作します。私もシリアル化が必要です。そのための解決策はありますか? –

+0

@Ben、バーチャルではないバーチャルな機能はほとんどありません。 'pointAccumulator'は抽象的なままです。私は物事をより簡単にすることを私が提案した方法を感じる。私は他の方法を見つけることはありません。 – iammilind

+1

私はそれを行っていますが、純粋に仮想関数を持つことは、私が思う工場クラスのためのより良いプログラミングテクニックです。私は本当にそれをバーチャルに保つことを望んでいました。 –

1

を参照してくださいフレンド関数の一例だと思います私は私のコメントを答えにします:

~/src/snips$ cat serializer-demo.cc 
#include <boost/archive/polymorphic_iarchive.hpp> 
#include <boost/archive/polymorphic_oarchive.hpp> 

typedef boost::archive::polymorphic_iarchive bpi; 
typedef boost::archive::polymorphic_oarchive bpo; 
typedef const unsigned int cui; 

struct ABC 
{ 
     virtual void serialize(bpi &ar, cui v) = 0; 
     virtual void serialize(bpo &ar, cui v) = 0; 
}; 

struct A : ABC 
{ 
     void serialize(bpi &ar, cui v) { ar & data; } 
     void serialize(bpo &ar, cui v) { ar & data; } 
     int data; 
     bool operator==(const A & rhs) const 
       { return data == rhs.data; } 
     A(int data=0) : data(data) {} 
}; 

#include <sstream> 
#include <boost/archive/polymorphic_text_iarchive.hpp> 
#include <boost/archive/polymorphic_text_oarchive.hpp> 

#include <boost/archive/polymorphic_binary_iarchive.hpp> 
#include <boost/archive/polymorphic_binary_oarchive.hpp> 
int main(int argc, char* argv[]) 
{ 
    const A a(1); 
    const ABC &abc = a; 
    A a1; 
    ABC &abc1 = a1; 
    { 
     std::stringstream ss; 
     { 
      boost::archive::polymorphic_text_oarchive oa(ss); 
      boost::archive::polymorphic_oarchive & oa_interface = oa; 
      oa_interface << abc; 
     } 
     { 
      boost::archive::polymorphic_text_iarchive ia(ss); 
      ia >> abc1; 
     } 
    } 
    if(! (a == a1)) 
     return 1; 
    { 
     std::stringstream ss; 
     { 
      boost::archive::polymorphic_binary_oarchive oa(ss); 
      oa << abc; 
     } 
     { 
      boost::archive::polymorphic_binary_iarchive ia(ss); 
      boost::archive::polymorphic_iarchive & ia_interface = ia; 
      ia_interface >> abc1; 
     } 
    } 
    if(! (a == a1)) 
     return 1; 
    return 0; 
} 

~/src/snips$ make -B serializer-demo 
g++ -o bin/serializer-demo --std=c++0x -g -O -march=native -pipe -Wall -Wno-parentheses -lboost_serialization serializer-demo.cc 
~/src/snips$ type -pa serializer-demo 
./bin/serializer-demo 
~/src/snips$ serializer-demo 
~/src/snips$ echo $? 
0 
~/src/snips$ 
+0

あなたの答えをありがとう、シリアル化メソッドがより高いクラスの内部で呼び出される場合にこれを使用する方法はありますか?現時点では、テンプレート「アーカイブ」がデフォルトでtext_iarchiveに設定されているため、多くのコンパイルエラーが発生しています。 –

+1

@Benテンプレート化されていないシリアライズは、ポリモーフィックの{i、o}アーカイブを取ります。あなたはストリーム上にアーカイブを構築することができます。私は子供と一緒にゲームしようとしていますので、他のアーカイブ上のアーカイブを気軽に構築して、あなたが望むように混在させることができるかどうかを探します。 – jthill

+0

コードをビルドするときにpolymorphic_binary_(i/o)アーカイブを使用していますが、メソッドを使用するたびにtext_(i/o)アーカイブとbinary_(i/o)アーカイブに一致する関数が存在しないという。 –

1

私はテンプレート化された関数の仮想化を偽装する面白い方法を持っています。 Faking a virtual templated function c++

これを階層に適用する必要がある場合、基本的な動機付けが適用されるかもしれませんが、この問題の実行時の解決策を可能にするためにboostメタプログラミングライブラリを利用することができます。