[RTTI] cast base class pointer to <templated> derived class pointer

Discussion in 'C++' started by tirath, Oct 12, 2003.

  1. tirath

    tirath Guest

    Hi all,

    I have a templated class that derives from a non-templated abstract class.
    How do I then cast a base class pointer to a <templated> derived class
    pointer in a generalised fashion?

    Here's what I'm generally trying to achieve:

    I'm building (trying to anyway) a serialization library. Here's my design:

    SPair<SP1, SP2> derives from Pair<P1,P2> and Ser:

    Ser <___________SPair <SP1, SP2>
    Pair<P1,P2> <____|

    Each time a Serializable Object (SObject) is created, the ctor registers the
    'this' pointer onto a serialisation list held statically in the abstract
    base class (Ser); the list holds Ser* - i.e. base class pointers. Each
    SObject's dtor is reponsible for removing the 'this' pointer from the list
    when the object falls out of scope (haven't implemented this yet).

    At some point, the user may call a static method Ser::Ser2Disk (at the
    moment just Ser::Ser2StdOut) that serializes all SObjects that have
    registered for serialization by iterating though the serialization list,
    which is a list of base class pointers. The problem is, what to do with the
    base class pointers that I get off the serialization list. (I had a look at
    the serialization stuff in the FAQ: the impression I got was that for
    serialisation, the way suggested is to simply call each SObject's
    Serialize() method... which is okay, but could be a lot better, why not with
    just a single Serialize()

    If I dynamic_cast the with full type information (as in `SPair<int, float>
    *ptr = dynamic_cast <SPair<int, float>*> (*i);`) I get the desired derived
    class, but how can I do this in a fully templated way? I suspect it may take
    a drastic change in design (since SPair<int, float> is essentially a
    different type than SPair<char *, double>). Any suggestions?

    I guess this is an RTTI related query? (I apologise if it isn't, for the
    misleading subject). I had a look at some RTTI related websites - all very
    interesting, but nothing that I found to be directly helpful with my
    problem. Also, according to "Dynamic Parallel Schedules framework" document
    on http://dps.epfl.ch/dpsdoc/x687.htm "Simple serialization should not be
    used on templated classes, since the IDENTIFY will not generate a correct
    class factory in this case. Use universal serialization instead"... but the
    universal serialization USAGE of that library looks daunting, I haven't even
    thought about the IMPLEMENTATION yet! And anyway I don't really care about
    circular structures and whatnot. So, let me basically restate what I am
    trying to achieve: how to I cast a base class pointer to a templated derived
    class pointer, or achieve the similar effect?

    best regards,
    -tirath ramdas

    p/s- this looks like a toughie, so credit will be given for all lines of
    code that were directly inspired by responses I get.

    Code follows...

    #define DEBUG // comment out to disable debugger methods

    #include <iostream>
    #include <list>
    #include "Types.h" // for "template <class P1, class P2> class Pair"

    using namespace std;

    class Ser {
    protected:
    virtual void ser_reg()=0;
    static list<Ser*> ser_list; // serialisation list
    public:
    #ifdef DEBUG
    virtual void WhoAmI()=0;
    static void Ser2StdOut(); // for debugging purposes
    #endif
    };

    // --------------------------- S E R P A I R S ---------------------------
    template <class SP1, class SP2>
    class SPair: public Ser, public Pair<SP1, SP2>
    {
    protected:
    void ser_reg() {
    ser_list.push_front(this); // register for serialisation
    }
    public:
    SPair(SP1 a, SP2 b):pair<SP1, SP2>(a,b){ // init data1, data 2
    ser_reg();
    cout << "\nCreated a " << typeid(this).name();
    } // init Pair, and call ser_reg method
    #ifdef DEBUG
    void WhoAmI(){cout << "\nSER PAIR @ " << (unsigned int)(this);}
    #endif

    };

    void Ser::Ser2StdOut()
    {
    list<Ser*>::const_iterator i;
    for(i=ser_list.begin(); i!=ser_list.end(); i++) {
    cout << endl << (unsigned int)*i << typeid(*i).name();
    SPair<int, float> *ptr = dynamic_cast <SPair<int, float>*> (*i);
    if(ptr!=NULL) cout << "found one!";
    }
    }
     
    tirath, Oct 12, 2003
    #1
    1. Advertising

  2. "tirath" <> wrote in message
    news:...
    ....
    > I'm building (trying to anyway) a serialization library. Here's my design:
    >
    > SPair<SP1, SP2> derives from Pair<P1,P2> and Ser:

    ....
    > the list holds Ser* - i.e. base class pointers.

    ....
    > At some point, the user may call a static method Ser::Ser2Disk (at the
    > moment just Ser::Ser2StdOut) that serializes all SObjects that have
    > registered for serialization by iterating though the serialization list,
    > which is a list of base class pointers. The problem is, what to do with

    the
    > base class pointers that I get off the serialization list. (I had a look

    at
    > the serialization stuff in the FAQ: the impression I got was that for
    > serialisation, the way suggested is to simply call each SObject's
    > Serialize() method... which is okay, but could be a lot better, why not

    with
    > just a single Serialize()


    What do you mean by a 'single' Serialize() ?
    AFAICT, different code needs to be generated for each template instance
    of SPair that is used in your program. (If not, please clarify...).
    The easiest way to generated these multiple Serialize() routines is to
    make Serialize() a member function of the SPair template.

    Then you still need a mechanism to access the Serialize() routine
    that matches the object instance you currently have a reference to.
    The native C++ way of doing this is to use a virtual method
    declared in the base class.

    Therefore:
    in class Ser:
    virtual void Serialize(_some_params_)=0;

    in template class SPair:
    virtual void Serialize(_some_params_)
    { /* code to serialize each member of the pair */ }

    > If I dynamic_cast the with full type information (as in `SPair<int, float>
    > *ptr = dynamic_cast <SPair<int, float>*> (*i);`) I get the desired derived
    > class, but how can I do this in a fully templated way? I suspect it may

    take
    > a drastic change in design (since SPair<int, float> is essentially a
    > different type than SPair<char *, double>). Any suggestions?


    Is there a reason why you do not want to consider a virtual method ?

    There are contorted ways to avoid using this simple and efficent
    approach (see "Modern C++ Design" to see how sophisticated things
    can become). But it is unclear to me why you do not want to use it here.


    Regards,
    Ivan
    --
    http://ivan.vecerina.com
     
    Ivan Vecerina, Oct 12, 2003
    #2
    1. Advertising

  3. tirath

    tirath Guest

    > Therefore:
    > in class Ser:
    > virtual void Serialize(_some_params_)=0;
    >
    > in template class SPair:
    > virtual void Serialize(_some_params_)
    > { /* code to serialize each member of the pair */ }
    >


    > Is there a reason why you do not want to consider a virtual method ?


    Not at all... pure ignorance on my part! I was under the impression that
    with a base class pointer you can ONLY get access to base class methods,
    even if the method was virtual (I thought virtual was just to allow a base
    class method to be overridden by a derived class' version). And anyway I
    could've sworn I tried it but it didn't work... the perils of writing C++
    too early in the morning/too late in the night!

    For UNserialization I think I will still need a fair bit of thinking to
    tackle the issue of templated types... or maybe theres something simple that
    I've misunderstood/overlooked, as has now again been proven to occur.

    Thanks very much Ivan.
     
    tirath, Oct 12, 2003
    #3
  4. Hi tirath,
    > For UNserialization I think I will still need a fair bit of thinking to
    > tackle the issue of templated types... or maybe theres something simple

    that
    > I've misunderstood/overlooked, as has now again been proven to occur.


    The typical solution is pretty much the one described in the FAQ:
    http://www.parashift.com/c -faq-lite/serialization.html#faq-35.8

    One function template you might find useful is something like:
    template<class T>
    Ser* SerCreate( istream src )
    { return new T(src); }

    You could rely on a map like the following to retrieve
    the factory function of each individual type:

    typedef Ser* (*SerCreatorF)( istream src );

    typedef std::map< std::string, SerCreatorF > SerCreatorsMap;
    SerCreatorsMap serCreators; // global var

    Each unserializable type then needs to be registered with
    something like:
    template<class T>
    void RegisterSer(std::string const& typeId)
    {
    SerCreatorF creatorFunc = &SerCreate<T>;
    serCreators["pair_int_float"] = creatorFunc;
    }

    Register each type with something like:
    RegisterSer<SPair<int,float> >("pair_int_float");

    NB: It would be tempting to use the compiler-generated type
    name that can be obtained with typeid(SomeType).name(),
    but this is unfortunately not portable.

    And, during unserialization, retrieve the polymorphic
    objects with something like:
    Ser* loadSerObject(istream src)
    {
    std::string typeID;
    src>> typeID;
    SerCreatorsMap::const_iterator pos = serCreators.find(typeID);
    if( pos == serCreators.end() )
    throw "UNKNOWN TYPE";

    return (pos->second)(src);
    }



    Regards,
    Ivan
    --
    http://ivan.vecerina.com
     
    Ivan Vecerina, Oct 12, 2003
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    407
    myork
    May 23, 2007
  2. Replies:
    1
    Views:
    398
    Victor Bazarov
    May 23, 2007
  3. Rasmus Johansen
    Replies:
    3
    Views:
    399
    VirGin
    Oct 18, 2007
  4. Replies:
    1
    Views:
    344
  5. , India
    Replies:
    8
    Views:
    983
    gwowen
    Aug 18, 2010
Loading...

Share This Page