Newsgroup: it.comp.lang.c++
Titolo: Domanda su metodi virtuali privati

Salve a tutti, ho qualche domanda su come strutturare dei metodi virtuali privati.
 
Il problema e': ho della classi che posso serializzare in un vettore di byte per la trasmissione su un canale radio, e che voglio poi deserializzare e ricostruire dall'altro lato.  Sto strutturando la cosa con una classe base "Serializable" che specifica l'interfaccia del meccanismo di (de)serializzazione, che viene poi implementato in dei metodi privati virtuali che le varie classi derivate devono implementare. Ad esempio, per una classe serializzabile 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&);
};
 
 
e A implementa serializeStep1 e deserializeStep1 a seconda di come e' fatta dentro.
 
Ora il mio problema e': la classe A e' a sua volta ereditata da altre classi (B1, B2, ecc.), quindi vorrei costruire una (de)serializzazione a cascata. Ad esempio, nella serializzazione di B1, il Bytestream deve avere prima la roba di A e a seguire la roba di B1; nella deserializzazione, A estrae la sua roba e poi B1 la propria.
 
Come fare?  L'unica cosa che mi viene in mente e' una cascata di metodi fatta cosi':
 
 
class A: public Serializable
{
private:
	virtual Bytestream serializeStep1();
	virtual Bytestream serializeStep2() = 0;
	virtual void deserializeStep1(Bytestream&);
	virtual void deserializeStep2(Bytestream&) = 0;
};
Bytestream Serializable::serialize() {
	return serializeStep1() + serializeStep2(); // il '+' concatena
}
void Serializable::deserialize(Bytestream&) {
	deserializeStep1(Bytestream&);
	deserializeStep2(Bytestream&);
}
 
 
class B1: public A
{
private:
	virtual Bytestream serializeStep2();
	virtual void deserializeStep2(Bytestream&);
}
 
 
 
ma non mi sembra una buona cosa, perche' A deve essere strutturata diversamente a seconda se viene ereditata da qualcuno oppure no.
 
Come fare?
 
Thx!
 

Errata: la classe A nel secondo caso e' ovviamente
 
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&);
} 
 
 
(A::serialize, non Serializable::serialize() )

 Come fare?
 
Senza entrare per ora nel merito, hai gia' dato un'occhiata ad 
http://www.parashift.com/c++-faq-lite/serialization.html
?
 
  bye
	av.

 (A::serialize, non Serializable::serialize() )
 
Forse la faccio troppo facile io, ma...
class A {
public:
    void deserialize() { /* deserializzazione A*/ }
}
class B : public A {
    void deserialize() { A::deserialize(); /* deserializzazione B */ }
}
etc.
 
Ciao!


Secondo me sbagli approccio, meglio una concatenazione di oggetti.
Ti butto una struttura (molto molto) semplificata di come potresti 
gestire la cosa (non far caso all'aver messo tutto in public e altro :-) 
è solo una base di esempio).
In pratica myStream implementa input e output, myObj è l'oggetto che 
gestisce i dati, in myInfoStream ci vanno le informazioni di cosa 
leggere/scrivere (ogni myObj ne implementa il proprio).
Quindi basta creare lo stream e passarlo al primo oggetto della catena.
Il serialize/deserialize lo puoi distinguere mettendo un flag nella 
classe che deriverai da myStream (o dove vuoi tu)
Ciao
---------------------
class myStream;
class myObj
{
   public:
     myObj() : next(0) {}
     virtual ~myObj {}
     virtual bool read(myStream*) = 0;
     virtual bool write(myStream*) = 0;
     virtual bool run(myStream* stream) {
       if(!read(stream))
         return false;
       if(!write(stream))
         return false;
       return next ? next->run(stream) : true;
       }
     myObj* next;
};
 
class myInfoStream
{
   public:
     virtual ~myInfoStream() {}
};
 
class myStream
{
   public:
     virtual ~myStream() {}
     virtual bool read(myInfoStream*) = 0;
     virtual bool write(myInfoStream*) = 0;
};
 
class myManager
{
   public:
     myObj* MyObj;
     bool run() {
       myStream* stream = buildStream();
       return MyObj->run(stream);
       }
}
 
 

 
http://www.parashift.com/c++-faq-lite/serialization.html
?
 
Si' l'avevo letto ma non tratta questo caso, assume che non ci sia un'intera gerarchia. Fa l'esempio base->derivata, ma non c'e' un base->derivata1->derivata2

 Ciao!
 
 
Si' questa e' la soluzione che probabilmente usero'. Alla fine non credo che ci sia un modo di girarci intorno, se ho base->deriv1->deriv2 e il metodo virtuale puro in base, allora:
* o la chiamata viene mandata a deriv1, che quindi poi deve fare un'ulteriore chiamata a deriv2 (l'esempio che ho scritto all'inizio)
* o la chiamata viene mandata a deriv2, che quindi deve chiamare "indietro" deriv1 un metodo che a quel punto sarebbe protetto (l'esempio che hai fatto tu)
 
La soluzione col metodo protetto mi sembra meno brutta da leggere :)


Privati non credo abbia molto senso, semmai protected in modo che le 
classi figlie possano ridefinire
 

 classi figlie possano ridefinire
 
Perche'?  Un metodo virtuale privato puo' essere ridefinito dalle classi derivate.


Puo darsi (non ho mai provato se sia possibile), ma lo considero cattivo 
design
E' piu logico usare protected o public
 

 Come fare?
 
Ma invece di fare tutti 'sti salti mortali, perch� non ridefinisci 
direttamente i metodi serialize e deserialize in modo diverso nelle due 
classi, cos� ogni classe si chiama il suo e morta l�?
 
In seconda battuta (ma la considero una mezza porcata) io farei un 
metodo virtuale serialize che richiama un altro metodo virtuale private 
o protected. Cos� hai i due livelli di virtualit� che ti servono per 
implementare due diversi tipi di serialize derivando in cascata... per� 
ripeto, io preferirei non ridurmi cos� :-)
 

PROVA
 


 
PROVA fallita. Vai su it.test per le prove.
 
-- 
Vincenzo Mercuri