Question on private virtual methods

Discussion in 'C++' started by plegdfmds@gmail.com, Jul 18, 2012.

  1. Guest

    Hi everyone,
    I have a question on how to structure some private virtual methods.

    MY problem is: I have some classes I need to serialize on a vector of bytesto be transmitted (and then reconstructed on the other end). What I want to do is having a class "Serializable" (inherited by all serializable classes) that specifies the interface of the (de)serialization mechanism, while the implementation is left to some private virtual methods that the derivedclasses need to implement. For example, for a class A:


    class Serializable
    {
    public:
    Bytestream serialize();
    void deserialize(Bytestream&);
    private:
    virtual Bytestream serializeStep1() = 0;
    virtual void deserializeStep1(Bytestream&) = 0;
    };
    Bytestream Serializable::serialize() {
    return serializeStep1();
    }
    void Serializable::deserialize(Bytestream&) {
    deserializeStep1(Bytestream&);
    }


    class A: public Serializable
    {
    private:
    virtual Bytestream serializeStep1();
    virtual void deserializeStep1(Bytestream&);
    };


    and A implements serializeStep1 e deserializeStep1 depending on its internal members.

    Now, my problem is: class A is itself inherited by classes B!, B2 etc. I'd like to build a "cascaded serialization": in the serialization of B1, firstA is serialized and then the internals of B1 are serialized and appended to the Bytestream.

    How to do this? The only thing I can think of is a cascade of private methods like this:


    class A: public Serializable
    {
    private:
    virtual Bytestream serializeStep1();
    virtual Bytestream serializeStep2() = 0;
    virtual void deserializeStep1(Bytestream&);
    virtual void deserializeStep2(Bytestream&) = 0;
    };
    Bytestream A::serialize() {
    return serializeStep1() + serializeStep2(); // il '+' concatena
    }
    void A::deserialize(Bytestream&) {
    deserializeStep1(Bytestream&);
    deserializeStep2(Bytestream&);
    }


    class B1: public A
    {
    private:
    virtual Bytestream serializeStep2();
    virtual void deserializeStep2(Bytestream&);
    }


    but it doesn't look good, because now I need to structure A differently depending whether it's inherited or not.

    How to do this?

    Thx!
     
    , Jul 18, 2012
    #1
    1. Advertising

  2. On 7/17/2012 8:02 PM, wrote:
    > I have a question on how to structure some private virtual methods.
    >
    > MY problem is: I have some classes I need to serialize on a vector
    > of

    bytes to be transmitted (and then reconstructed on the other end). What
    I want to do is having a class "Serializable" (inherited by all
    serializable classes) that specifies the interface of the
    (de)serialization mechanism, while the implementation is left to some
    private virtual methods that the derived classes need to implement. For
    example, for a class A:
    >
    >
    > class Serializable
    > {
    > public:
    > Bytestream serialize();
    > void deserialize(Bytestream&);
    > private:
    > virtual Bytestream serializeStep1() = 0;
    > virtual void deserializeStep1(Bytestream&) = 0;
    > };
    > Bytestream Serializable::serialize() {
    > return serializeStep1();
    > }
    > void Serializable::deserialize(Bytestream&) {
    > deserializeStep1(Bytestream&);
    > }


    I don't think it's warranted. Or, your class is misnamed, and should be
    named 'SerializableInStep1'.

    >
    >
    > class A: public Serializable
    > {
    > private:
    > virtual Bytestream serializeStep1();
    > virtual void deserializeStep1(Bytestream&);
    > };
    >
    >
    > and A implements serializeStep1 e deserializeStep1 depending on its

    internal members.
    >
    > Now, my problem is: class A is itself inherited by classes B!, B2
    > etc.

    I'd like to build a "cascaded serialization": in the serialization of
    B1, first A is serialized and then the internals of B1 are serialized
    and appended to the Bytestream.
    >


    Looks like B1's implementation should just call the base class'
    *protected* member.

    > How to do this? The only thing I can think of is a cascade of
    > private

    methods like this:
    >
    >
    > class A: public Serializable
    > {
    > private:
    > virtual Bytestream serializeStep1();
    > virtual Bytestream serializeStep2() = 0;
    > virtual void deserializeStep1(Bytestream&);
    > virtual void deserializeStep2(Bytestream&) = 0;
    > };
    > Bytestream A::serialize() {
    > return serializeStep1() + serializeStep2(); // il '+' concatena
    > }
    > void A::deserialize(Bytestream&) {
    > deserializeStep1(Bytestream&);
    > deserializeStep2(Bytestream&);
    > }
    >
    >
    > class B1: public A
    > {
    > private:
    > virtual Bytestream serializeStep2();
    > virtual void deserializeStep2(Bytestream&);
    > }
    >
    >
    > but it doesn't look good, because now I need to structure A
    > differently depending whether it's inherited or not.


    A couple of comments. Generally, design is out of scope in a language
    newsgroup, unless it's language-specific, and here it's not. Second,
    your 'Serializable' class imposes an unnecessary limitation on the
    derived classes, IMO, to implement the 'step1' interface. What for?
    Just force the derived classes to implement 'serialize' and 'de-'
    methods, and let them decide how to perform [de]serialization. Third,
    if you want sequential serialization, perhaps a policy is a better way.
    See 'Modern C++ Design' by Alexandrescu.

    Perhaps if you elaborated a bit more on *why* step1 and step2 are the
    model requirements, it would be a bit more obvious... I know, it's not
    much of help, but without knowing the underlying model, it's kind of
    hard to recommend any particular solution or even evaluate the presented
    solution. Sorry.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 18, 2012
    #2
    1. Advertising

  3. Guest

    > I don't think it's warranted. Or, your class is misnamed, and should be
    > named 'SerializableInStep1'.


    What do you mean?



    > Looks like B1's implementation should just call the base class'
    > *protected* member.


    I could do that, yes. But I wanted to see if there's a way to call "forward" from the base to the derived, and not the other way.


    > Second,
    > your 'Serializable' class imposes an unnecessary limitation on the
    > derived classes, IMO, to implement the 'step1' interface. What for?
    > Just force the derived classes to implement 'serialize' and 'de-'
    > methods, and let them decide how to perform [de]serialization.


    To separate the interface from the implementation. There's some more stuff in Serializable::serialize() that I didn't show because it's not relevant here; it looks more like:

    Bytestream Serializable::serialize() {
    [steps common to all serializable classes]
    serializeStep1();
    [more steps common to all serializable classes]
    }

    so the Serializable class defines the inetrface and the common steps, and the derived classes just implement what they need to implement.
     
    , Jul 18, 2012
    #3
  4. On 18.07.2012 02:02, wrote:
    > Hi everyone,


    "Content-Transfer-Encoding: quoted-printable"

    ^ Why are you doing that? The *ONLY* effect is to screw up things. It
    was invented for passing mails across 7-bit hosts: there are no more
    such hosts today.


    > I have a question on how to structure some private virtual methods.


    No, you have an XY question.

    You have a problem X, for which you have devised an idea of solution Y.

    The idea Y is ungood in many respects, so you're asking about how to fix
    it, instead of more reasonably asking about how to do X.

    However, you're not the first to do that XY confusion thing for this
    particular question.

    Even the Boost guys did it.


    > MY problem is: I have some classes I need to serialize on a vector of bytes
    > to be transmitted (and then reconstructed on the other end). What I want
    > to do is having a class "Serializable" (inherited by all serializable
    > classes) that specifies the interface of the (de)serialization mechanism,
    > while the implementation is left to some private virtual methods that the
    > derived classes need to implement.


    Deserialization cannot, IMHO, reasonably be done via virtual methods in
    the class to be deserialized, because with deserialization you want to
    pass the relevant information to *constructors*.

    In other words, nearly all extant serialization/deserialization library
    solutions for C++, including Boost serializations, are unreasonable:
    they're at cross purposes with the C++ language design.

    That said, once you choose this unreasonable almost-solution, which
    requires you to create zombie objects that then are initialized via
    deserialization, just go with the flow. You have then already dispensed
    with the main C++ ideals, so there's NO POINT in desperately holding on
    to some very much lesser design level C++ ideals such as private
    overrides. That would be like unthinkingly defecating on the floor of a
    restaurant (with other guests watching), and then desperately trying to
    be polite when asking other guests at the restaurant for toilet paper.
    Hey, politeness went down the drain, so to speak, with the defecation
    action. It's just absurd to then cling to the lesser ideals!


    > For example, for a class A:
    >
    >
    > class Serializable
    > {
    > public:
    > Bytestream serialize();
    > void deserialize(Bytestream&);
    > private:
    > virtual Bytestream serializeStep1() = 0;
    > virtual void deserializeStep1(Bytestream&) = 0;
    > };
    > Bytestream Serializable::serialize() {
    > return serializeStep1();
    > }
    > void Serializable::deserialize(Bytestream&) {
    > deserializeStep1(Bytestream&);
    > }
    >
    >
    > class A: public Serializable
    > {
    > private:
    > virtual Bytestream serializeStep1();
    > virtual void deserializeStep1(Bytestream&);
    > };
    >
    >
    > and A implements serializeStep1 e deserializeStep1 depending on its internal members.
    >
    > Now, my problem is: class A is itself inherited by classes B!, B2 etc. I'd like to
    > build a "cascaded serialization": in the serialization of B1, first A is serialized
    > and then the internals of B1 are serialized and appended to the Bytestream.


    Well, as I understand it the Boost guys at one point seriously
    considered using Johannes' infamous access of private methods, for this.
    See his blog entry "Access to private members. That's easy!", at <url:
    http://bloglitb.blogspot.no/2010/07/access-to-private-members-thats-easy.html>.
    But don't do that: instead, make the methods protected. Remember, the
    defecation has already happened, by the choice of in-class virtual
    functions for deserialization, i.e. by not using constructors, and
    having zombie objects around. More politeness after that is just absurd.


    > How to do this? The only thing I can think of is a cascade of
    > private methods like this:


    Well, you could add non-private methods, but that's equally absurd.

    Just go with the flow.

    Or do it properly.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jul 18, 2012
    #4
  5. On Jul 18, 7:59 am, "Alf P. Steinbach" <alf.p.steinbach
    > wrote:
    > On 18.07.2012 02:02, wrote:
    >
    > > Hi everyone,

    >
    > "Content-Transfer-Encoding: quoted-printable"
    >
    > ^ Why are you doing that? The *ONLY* effect is to screw up things. It
    > was invented for passing mails across 7-bit hosts: there are no more
    > such hosts today.
    >
    > > I have a question on how to structure some private virtual methods.

    >
    > No, you have an XY question.
    >
    > You have a problem X, for which you have devised an idea of solution Y.
    >
    > The idea Y is ungood in many respects, so you're asking about how to fix
    > it, instead of more reasonably asking about how to do X.
    >
    > However, you're not the first to do that XY confusion thing for this
    > particular question.
    >
    > Even the Boost guys did it.
    >
    > > MY problem is: I have some classes I need to serialize on a vector of bytes
    > > to be transmitted (and then reconstructed on the other end).  What I want
    > > to do is having a class "Serializable" (inherited by all serializable
    > > classes) that specifies the interface of the (de)serialization mechanism,
    > > while the implementation is left to some private virtual methods that the
    > > derived classes need to implement.

    >
    > Deserialization cannot, IMHO, reasonably be done via virtual methods in
    > the class to be deserialized, because with deserialization you want to
    > pass the relevant information to *constructors*.
    >
    > In other words, nearly all extant serialization/deserialization library
    > solutions for C++, including Boost serializations, are unreasonable:
    > they're at cross purposes with the C++ language design.


    could you expand on this? I tried to implement serialization using
    constructors
    and didn't quite get it to gell.

    Would you use a constructor like this
    Serializable (istream&)

    The touble is until you've read at least some of the object you don't
    know its type. I ended up with some sort of factory that cloned
    registered objects.

    The C++ FAQ has a serialization section
    http://www.parashift.com/c -faq-lite/serialization.html

    what the hell happened to the format!?


    <snip>


    > >  For example, for a class A:

    >
    > > class Serializable
    > > {
    > > public:
    > >          Bytestream serialize();
    > >          void deserialize(Bytestream&);
    > > private:
    > >          virtual Bytestream serializeStep1() = 0;
    > >          virtual void deserializeStep1(Bytestream&) = 0;
    > > };
    > > Bytestream Serializable::serialize() {
    > >          return serializeStep1();
    > > }
    > > void Serializable::deserialize(Bytestream&) {
    > >          deserializeStep1(Bytestream&);
    > > }

    >
    > > class A: public Serializable
    > > {
    > > private:
    > >          virtual Bytestream serializeStep1();
    > >          virtual void deserializeStep1(Bytestream&);
    > > };

    >
    > > and A implements serializeStep1 e deserializeStep1 depending on its internal members.

    >
    > > Now, my problem is: class A is itself inherited by classes B!, B2 etc. I'd like to
    > > build a "cascaded serialization": in the serialization of B1, first A is serialized
    > > and then the internals of B1 are serialized and appended to the Bytestream.

    >
    > Well, as I understand it the Boost guys at one point seriously
    > considered using Johannes' infamous access of private methods, for this.
    > See his blog entry "Access to private members. That's easy!", at <url:http://bloglitb.blogspot.no/2010/07/access-to-private-members-thats-e...>.
    > But don't do that: instead, make the methods protected. Remember, the
    > defecation has already happened, by the choice of in-class virtual
    > functions for deserialization, i.e. by not using constructors, and
    > having zombie objects around. More politeness after that is just absurd.
    >
    > > How to do this?  The only thing I can think of is a cascade of
    > > private methods like this:

    >
    > Well, you could add non-private methods, but that's equally absurd.
    >
    > Just go with the flow.
    >
    > Or do it properly.
    >
     
    Nick Keighley, Jul 18, 2012
    #5
  6. On 18.07.2012 19:49, Leigh Johnston wrote:
    >
    > struct bar : foo
    > {
    > bar() {}
    > bar(const i_stream& p) : foo() { deserialize(p); }
    > virtual void deserialize(const i_stream& p) { foo::deserialize(p);
    > p >> c; p >> d; }
    > virtual void serialize(i_stream& p) { foo::serialize(p); p << c; p
    > << d; }
    > int c;
    > std::string d;
    > };
    >
    > Works quite well.


    uhm, perhaps the stream is a little bit too immutable?


    cheers,

    - Alf
     
    Alf P. Steinbach, Jul 18, 2012
    #6
  7. Guest

    On Wednesday, July 18, 2012 1:49:01 PM UTC-4, Leigh Johnston wrote:
    >
    > I use something like the following to handle serialization:
    >
    > struct i_stream
    > {
    > // functions to encode/decode types to/from a stream ...
    > };
    >
    > struct i_serializable
    > {
    > virtual void deserialize(const i_stream&amp; p) = 0;
    > virtual void serialize(i_stream&amp; p) = 0;
    > };
    >
    > struct foo : i_serializable
    > {
    > foo() {}
    > foo(const i_stream&amp; p) { deserialize(p); }
    > virtual void deserialize(const i_stream&amp; p) { p &gt;&gt; a; p &gt;&gt; b; }
    > virtual void serialize(i_stream&amp; p) { p &lt;&lt; a; p &lt;&lt; b; }
    > int a;
    > std::string b;
    > };
    >
    > struct bar : foo
    > {
    > bar() {}
    > bar(const i_stream&amp; p) : foo() { deserialize(p); }
    > virtual void deserialize(const i_stream&amp; p) { foo::deserialize(p); p &gt;&gt;
    > c; p &gt;&gt; d; }
    > virtual void serialize(i_stream&amp; p) { foo::serialize(p); p &lt;&lt; c; p &lt;&lt; d; }
    > int c;
    > std::string d;
    > };
    >
    > Works quite well.
    >



    The C++ Middleware Writer automates the writing of marshalling
    functions. For example, a user adds function prototypes to
    his class like this:

    class cmw_account_info {
    ::cmw::marshalling_integer accountnumber;
    ::std::string password;

    cmw_account_info ()
    {}

    template <class R>
    explicit cmw_account_info :):cmw::ReceiveBuffer<R>& buf);

    void CalculateMarshallingSize :):cmw::Counter& cntr) const;
    void MarshalMemberData :):cmw::SendBuffer& buf) const;
    void Marshal :):cmw::SendBuffer& buf, bool = false) const
    {
    MarshalMemberData(buf);
    }
    };


    The C++ Middleware Writer maintains the implementations
    of the function prototypes for you.


    Shalom,
    Brian
    Ebenezer Enterprises
    http://webEbenezer.net
     
    , Jul 19, 2012
    #7
    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. qazmlp
    Replies:
    19
    Views:
    828
    Daniel T.
    Feb 4, 2004
  2. John Goche
    Replies:
    10
    Views:
    797
    Marcus Kwok
    Dec 8, 2006
  3. earthwormgaz
    Replies:
    3
    Views:
    364
    Michael Doubez
    Mar 11, 2010
  4. Daniel Finnie
    Replies:
    3
    Views:
    210
    Logan Capaldo
    Dec 16, 2006
  5. Frank Meyer

    Private methods not so private?

    Frank Meyer, Aug 1, 2007, in forum: Ruby
    Replies:
    14
    Views:
    304
Loading...

Share This Page