Newsgroup: it.comp.lang.c++
Titolo: Problema: Overload di <<

Salve,
    il problema è il seguente:
class TLogError
{
public:
 TLogError();
 TLogError& operator <<(CString&);
 TLogError& operator <<(char*);
....
};
class TLogSpriteError : public TLogError
{
public:
 TLogSpriteError();
 using  TLogError::operator <<;
 TLogSpriteError& operator <<(LONGLONG);
};
 Come faccio ad evitare che il seguente codice mi dia errore:
CString A="ciao";
LONGLONG N=50;
TLogSpriteError S;
S<<A<<N<<"ora basta!";
Errore: error C2678: binary '<<' : no operator defined which takes a
left-hand operand of type 'class TLogError' (or there is no acceptable
conversion)
Ho provato anche il seguente codice:
     TLogError& operator <<(LONGLONG);
al posto di
     TLogSpriteError& operator <<(LONGLONG);
Grazie, Lorenzo.

 S<<A<<N<<"ora basta!";
Il problema, naturalmente, e` che l'espressione "S<<A"
ha come valore un TLogError&, poiche` cosi` hai scelto
di dichiarare la TLogError::operator<<(CString&) [un
aspetto strano di questa dichiarazione e` che dice che
questo metodo modifica il suo argomento CString; forse
intendi const CString&...?].
E su TLogError, l'overload di operator<<(LONGLONG)
non e` definito.
Potresti ridefinire gli operator<< di TLogSpriteError in
modo che tornino un TLogSpriteError& piuttosto che un
meno specifico TLogError&.  Naturalmente, questo non
lascerebbe gran che della "eredita` di implementazione"
che stai cercando di fare, rendendola equivalente e anzi
piu` goffa di un contenimento + delegazione.
Un'altra possibilita` per ottenere un migliore riuso del
codice e` quella di ricorrere ai template e alla famosa
"pattern without a name" -- ad esempio:
template<class ActualDerivedClass>
class TLogError {
    public:
        ActualDerivedClass& operator<<(const char*);
    // ecc
};
class TLogSpriteError: public TLogError<TLogSpriteError>
{
    public:
    typedef TLogError<TLogSpriteError> BaseClass;
    using  BaseClass::operator <<;
    // ecc
};
Non sono ne` l'unico ne` il primo ad avere osservato che
questa pattern e` spesso il modo migliore di ottenere quel
riuso di codice (con poca o nessuna boilerplate) che viene
invece classicamente cercato nella eredita` d'implementazione.
James O. Coplien (noto autore di "Multi-Paradigm DESIGN
for C++", "Advanced C++", ecc) e` colui che ha per primo
identificato questa pattern (trovandone esempi nei posti
piu` vari) e l'ha pubblicata (col pessimo, secondo me, nome
di "The pattern without a name" -- ma non dovrei lamentarmi,
penso, visto che a Bologna abbiamo anche "Via Senza Nome"!-).
Trovi molti buoni esempi della pattern, ad esempio, nelle
Active Template Libraries (ATL) della Microsoft.
O template/generic-programming, o boilerplate, direi... a
te la scelta.
Alex

 };
A cosa serve lo "using" in quel contesto?
Ciao!
-----
Giovanni Bajo
Lead Programmer
Prograph Research S.r.l.
http://www.prograph.it

 A cosa serve lo "using" in quel contesto?
A esporre il nome lessicalmente tratto dalla classe base
nel suo ruolo, appunto, lessicale, cioe` di spazio dei
nomi.  Se il nome non fosse esposto, verrebbe nascosto
(secondo la normale operazione degli scope annidati)
dagli altri overload di operator<< contenuti dalla classe
TLogSpriteError.
Alex