Question on private virtual methods

P

plegdfmds

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!
 
V

Victor Bazarov

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
 
P

plegdfmds

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.
 
A

Alf P. Steinbach

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
 
N

Nick Keighley

"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.


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.


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!?
 
A

Alf P. Steinbach

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
 
W

woodbrian77

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top