Newsgroup: it.comp.lang.c++
Titolo: problema di ereditarieta'

salve a tutto il ng,
mi scuso della probabile domanda da newbie, ma tutte le volte che mi
metto a programmare in C++ mi sorgono dei dubbi esistenziali sulla
risoluzione dei problemi che mi trovo davanti, e quindi mi piace leggere 
pareri e stili diversi per risolverli.
Ho il seguente problema: siano A, B e C tre classi con parentela
A->B->C
ciascuna classe possiede dei dati membro, che vengono controllati da una
funzione membro opportuna, check(), definita virtuale. Trattandosi
ciascuna classe di specializzazioni successive della classe A, la
mia implementazione prevede che A::check() controlli i dati membro di A,
B::check() faccia questo controllo sui dati membro di B e ovviamente
C::check() lo faccia su quelli di C.
Inoltre, affinche' il controllo avvenga su tutti i dati della classe, ho 
ritenuto corretto sviluppare un meccanismo a cascata, in cui 
l'implementazione C::check() chiamera' B::check() che a sua volta 
chiamera' A::check().
Ovviamente, dato che la funzione e' virtuale, accedendo a check() 
attraverso un A *ptr, ptr->check() chiamera' C::check(), avviando la 
cascata e controllando tutta la classe C, compresi i dati membro ereditati.
Fin qui tutto bene. Il problema sorge nel momento in cui devo ripetere
tale logica per un'altra funzione, commit(), che prima di effettuare il
commit dei dati per C, B ed infine A (scendendo nella stessa maniera) 
deve chiamare check() per controllare se sono validi.
Se in C::commit() metto una chiamata a C::check(), esso dopo scendera' 
in B::check() e A::check(), il che potrebbe andare bene. Ho il pieno 
controllo della classe a cui seguira' il commit a cascata.
In pratica, solo il figlio di testa deve chiamare check().
Se infatti anche B::commit() chiamasse B::check(), quando C::commit() 
scende in cascata a B::commit() si rioetterrebbe un effetto cascata sui 
check B e A.
il fatto che solo il figlio di testa debba chiamare la sua check mi 
secca alquanto, dal punto di vista formale. Se impaccassi tutto quanto 
in una libreria, e poi implementassi una classe D figlia di C, sarebbe 
un grosso problema: ora il figlio di testa e' D, e C con la sua chiamata 
creerebbe inutili chiamate a check gia' effettuati.
voi come risolvereste questo problema? pensavo a flag per inibire la 
chiamata, ma mi piace poco. Un'altra soluzione sarebbe avere, per ogni 
classe, una funzione membro checkAdata(), checkBdata(), checkCdata() e 
fare in modo che check() chiami la sua funzione e poi avvii la cascata, 
e lo stesso faccia commit. In questo modo ognuno segue il suo percorso, 
senza causare problemi. Di seguito propongo un piccolo codice di esempio
relativo al problema che incontro.
#include <iostream>
class A
{
     public:
         virtual void check();
         virtual void commit();
};
class B: public A
{
     public:
         virtual void check();
         virtual void commit();
};
class C: public B
{
     public:
         virtual void check();
         virtual void commit();
};
void A::check()
{
     cout << "I am the A : check" << endl;
}
void B::check()
{
     A::check();
     cout << "I am the B : check" << endl;
}
void C::check()
{
     B::check();
     cout << "I am the C : check" << endl;
}
void A::commit()
{
     A::check();
     cout << "I am the A : commit" << endl;
}
void B::commit()
{
     B::check();
     A::commit();
     cout << "I am the B : commit" << endl;
}
void C::commit()
{
     C::check();
     B::commit();
     cout << "I am the C : commit" << endl;
}
int main( int argc, char **argv )
{
     C c;
     A *a = &c;
     a->commit();
     return 0;
}
Vi ringrazio dell'attenzione

 deve chiamare check() per controllare se sono validi.
Vedi se qualcosa del genere ti può andare bene:
#include <iostream>
class A
{
    public:
        virtual void check();
        virtual void commit( bool docheck = true );
};
class B: public A
{
    public:
        void check();
        void commit( bool docheck = true );
};
class C: public B
{
    public:
        void check();
        void commit( bool docheck = true );
};
void A::check()
{
    std::cout << "I am the A : check" << std::endl;
}
void B::check()
{
    A::check();
    std::cout << "I am the B : check" << std::endl;
}
void C::check()
{
    B::check();
    std::cout << "I am the C : check" << std::endl;
}
void A::commit( bool docheck )
{
    if ( docheck ) check();
    std::cout << "I am the A : commit" << std::endl;
}
void B::commit( bool docheck )
{
    if ( docheck ) check();
    A::commit( false );
    std::cout << "I am the B : commit" << std::endl;
}
void C::commit( bool docheck )
{
    if ( docheck ) check();
    B::commit( false );
    std::cout << "I am the C : commit" << std::endl;
}
int main()
{
    A a;
    B b;
    C c;
    A *ap[ 3 ] = { &a, &b, &c };
    ap[ 0 ] -> commit(); std::cout << '\n';
    ap[ 1 ] -> commit(); std::cout << '\n';
    ap[ 2 ] -> commit();
    return 0;
}
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg

 wrote:
se non ho capito male, vuoi questo: 
// code
#include <iostream>
class A
{
 protected:
    virtual void commit()
    { std::cout << "A::commit()" << std::endl; }
    virtual void check()
    { std::cout << "A::check()" << std::endl;  }
 public:
    virtual ~A(){}
 
    void check_and_commit()
    {
        check();
        commit();        
    }
};
class B: public A
{ 
 protected:
    virtual void commit()
    {
        A::commit();
        std::cout << "B::commit()" << std::endl;
    }
 
    virtual void check()
    {
        A::check();
        std::cout << "B::check()" << std::endl;
    }
};
class C :public B
{ 
 protected:
    virtual void commit()
    {
        B::commit();
        std::cout << "C::commit()" << std::endl;
    }
 
    virtual void check()
    {
        B::check();
        std::cout << "C::check()" << std::endl;
    }
};
int main()
{
    A* anA = new C;
    anA->check_and_commit();
    delete anA;
}
//end code
// out:
A::check()
B::check()
C::check()
A::commit()
B::commit()
C::commit()
in sostanza hai due stupidfunctions virtuali che fanno un unica cosa
(checkare i dati O eseguire il comando)
ed una funzione non virtuale pubblica della base che risolve il lavoro
polimorficabrudusdusmente. 
interfaccia semplice, poco codice da scrivere per aumentare la
gerarchia (e non ti servono i flag che volevi mettere).
sempre che io non abbia frainteso cosa intendevi.
sbirish.


A parte un
using namespace std;
che se non metti all'inizio il tuo programma non compila, l'output è il
seguente
I am the A : check
I am the B : check
I am the C : check
I am the A : check
I am the B : check
I am the A : check
I am the A : commit
I am the B : commit
I am the C : commit
Come vedi fail il chek di C una volta, quello di B due volte e quello di A
tre volte. Hai sicuramente dei problemi architetturali.
Ciò è dovuto alla doppia ricorsività in commit e check. Devi decidere quale
portare avanti. Per il resto non sono sicuro di sapere quale sia il tuo
problema.