Virtual functions and template clash

2019-02-18 06:38发布

问题:

I have an abstract base class for a pointAccumulator. This abstract base will be filled out with methods such as a function that returns mean of all the points. An example of these two classes is shown below:

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_;
};

As you can see in the code I would also like to use boost serialization in to save these types. Now using a factory pattern i believe that you call the pointAccumulator types like this:

lala *a1 = new lalaLower();

My problem is that the templated serialize method will not be accessible if I call it this way. Also I cannot have the templated class in the abstract class as this is not allowed by c++. Is there a way to get around this?

Edit:

I have considered the non-intrusive method for serialization but that requires heights_ to be public which is not ideal, nor is it good programming style. I thought potentially a method using friend classes or functions could penetrate the class with access to the variables while still keeping the base class abstract? can anyone explain how this would work?

回答1:

I think using friend classes or functions is a good solution, you could add new class like Serializor

here is a example of friend function

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& );

};

refer to http://msdn.microsoft.com/en-us/library/ahhw8bzz.aspx



回答2:

I believe you cannot do it without wrapping Archive type parameter into polymorphic hierarchy this way or another.

It seems though that Boost.Serialization does it for you.



回答3:

As you may know that templates and virtual methods don't go hand in hand.

I would suggest to remove the meanAccumulator::serialize() method and add into class pointAccumulator body and call the virtual functions inside wherever they are needed.
You can also think of passing a handle of derived class and call the method with that.

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
  }
};

The only thing which you need to take care is that, whatever non-virtual methods you call inside serialize() using derived handle --> should be of same name in all the children classes from pointAccumulator, irrespective of what they do inside.



回答4:

In fact, I'll make my comment an answer:

~/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$ 


回答5:

So I have an interesting way of faking virtualism for templated functions. Faking a virtual templated function c++

The basic motivation might be applied here if you need this enforced in the hierarchy, but you can utilize boost meta programming library to allow a run-time solution for this problem.