C ++ Member function template in a derived class, how to call it from a base class?

Since my preliminary question seemed confusing, I think it is best to clearly state what I want to achieve.

I have (ignore inheritance now and focus on X):

class Base {};

class X : public Base {
private:
    double m_double;
public:
    template<class A> friend 
    void state( A& a, const X& x ) {
        data( a, x.m_double, "m_double" );
    }   
};

Now I can introduce arbitrary new classes that perform different actions depending on how the data function is overloaded, we will refer to them as Accessors in the following:

class XmlArchive {...}; //One Accessor
template<class T>
void data( XmlArchive& a, const T& t, const std::string& str ) {
//read data and serialize it to xml Archive
}

class ParameterList {...}; //Another Accessor
template<class T>
void data( ParameterList& a, const T& t, const std::string& str ) {
//put data in a parameter list 
}

Then I can write:

X myX;

XmlArchive myArchive;
state( myArchive, myX );

ParameterList myParameters;
state( myParameters, myX );

Fantastic, code reuse !: D However, the following (explicitly) fails:

Base* basePtr = new X; //This would come from factory really, I should not know the type X
state( myParameters, *basePtr ); //Error

The goal is to make this last challenge a success. What I reviewed (and why this is unacceptable):

First option: make all Accessors inherit from a common base class, such as AccessorBase, and then write to Base

virtual state( AccessorBase& a ) const = 0;

X ( , ). , AccessorBase , (-) . (. , X, Y ), , .

: Accessor. open/close, Accessor (, TxtArchive) .

, - ( vtbls ). , ... , X, Accessor , ( XmlArchive):

state( xmlArchive, x ); //xmlArchive of type XmlArchive, x of type X

.

, :

state( myParameters, *basePtr );

basePtr , , .

, boost:: serialize - , , (, ++ , This(), , ...)

!

+3
4

vistor:

class IVisitor
{
  public:
    virtual void on_data( double, const char * )=0;
    virtual void on_data( std::string, const char * )=0;
}; 

class Base 
{
  public:
    virtual void visit( IVisitor * v )=0;
};

class X : public Base 
{
  private:
    double m_double;
    std::string m_string;
  public:
    void visit( IVisitor * v)
    {
        v->on_data( m_double, "m_double" );
        v->on_data( m_string, "m_string" );
    }   
};

Base * base = ...;
XmlArchive ar;  // This must derive from IVisitor
base->visit(&ar);
ParameterList pl; // This must derive from IVisitor
base->visit(pl);

on_data IVisitor, boost::any, , , , , .

+1

, dynamic_cast C, , X, Base * X * ( ). , , X, Y Z , , RTTI.

, :

X::state( myParameters, *(X*)(basePtr) );

RTTI:

X::state( myParameters, *dynamic_cast<X*>(basePtr) );

X, Y, Z wth Z:: state, Y:: state X:: state, , basePtr.

switch(basePtr->get_type())
{
    case TYPE_X:
        X::state( myParameters, *(X*)(basePtr) );
        break;
    case TYPE_Y:
        Y::state( ... );
        break;
}

.

+1

, , , , :

class StateBase {
  virtual void state() = 0;
};

template<typename T>
class StateMixin : public StateBase {
  void state() {
    T::data();
  }
};

class MyType : public StateMixin<MyType>
{
  void data() {};
}

Here state () is defined using StateMixin and can be called from any instance of StateBase, but it is separately created by the compiler instance for each user type that implements data.

0
source

Add a friend’s ad to your base to become

class Base 
{
   template<class A> friend void state( A& a, const X& x );
};
0
source

Source: https://habr.com/ru/post/1747208/


All Articles