2010-12-31 21 views
36

Devo utilizzare un operatore virtuale < <. Tuttavia, quando provo a scrivere:Operatore rendere << virtuale?

virtual friend ostream & operator<<(ostream& os,const Advertising& add); 

ottengo l'errore del compilatore

Errore 1 Errore C2575: 'operatore < <': solo funzioni membro e basi possono essere virtuale

Come posso trasformare questo operatore virtuale?

risposta

63

Il problema con questa configurazione è che l'operatore < < definito sopra è una funzione libera, che non può essere virtuale (non ha oggetto ricevitore). Per rendere la funzione virtuale, deve essere definita come membro di una classe, il che è problematico qui perché se si definisce l'operatore < < come membro di una classe, gli operandi saranno nell'ordine errato:

class MyClass { 
public: 
    virtual ostream& operator<< (ostream& out) const; 
}; 

significa che

MyClass myObject; 
cout << myObject; 

non si compila, ma

MyClass myObject; 
myObject << cout; 

sarà legale.

Per risolvere questo problema, è possibile applicare il Teorema fondamentale dell'ingegneria del software: qualsiasi problema può essere risolto aggiungendo un altro livello di riferimento indiretto. Piuttosto che fare operatore < < virtuale, considerare l'aggiunta di una nuova funzione virtuale per la classe che assomiglia a questo:

class MyClass { 
public: 
    virtual void print(ostream& where) const; 
}; 

Poi, definire operatore < < come

ostream& operator<< (ostream& out, const MyClass& mc) { 
    mc.print(out); 
    return out; 
} 

In questo modo, l'operatore < < la funzione libera ha l'ordine dei parametri corretto, ma il comportamento dell'operatore < < può essere personalizzato in sottoclassi.

Spero che questo aiuti!

+0

grazie è molto utile. ho pensato a questa soluzione, ma ho pensato che forse c'è un altro modo in cui non lo so più facile per l'implementazione. –

+4

* "qualsiasi problema può essere risolto aggiungendo un altro livello di riferimento indiretto" * - ricorda, qualsiasi problema eccetto il problema di troppi livelli di riferimento indiretto;) – Kos

+12

@Kos: No, no. Finché l'hai dichiarato "indiretto senza segno", devi solo aggiungere sempre più indiretta e il problema si risolverà da solo quando cambi il valore di –

2

Sembra che si desideri veramente fornire funzionalità di output per una gerarchia di classi e, in tal caso, è possibile fornire un friend operator << che chiama una funzione virtual.

class Parent 
{ 
public: 
    friend std::ostream& operator<< (std::ostream& os, const Parent& p); 
    // ... other class stuff 
protected: 
    virtual void printMyself(std::ostream& os) const 
    { 
     // do something if you must, or make this a pure virtual 
    } 
}; 

std::ostream& operator<< (std::ostream& os, const Parent& p) 
{ 
    p.printMyself(os); 
    return os; 
} 

class Child : public Parent 
{ 
    // other class stuff... 
protected: 
    virtual void printMyself(std::ostream os) const 
    { 
     // whatever you need to do 
    } 
}; 

dettagliato anche nella C++ FAQ

25

Definite il vostro operatore di < < per chiamare un metodo di stampa virtuale:

class Base 
{ 
    protected: 
     virtual void print(std::ostream& str) const = 0; 
    public: 
     friend std::ostream& operator<<(std::ostream& str, Base const& data) 
     { 
      data.print(str); 
      return str; 
     } 
} 
+1

, probabilmente si intende 'data.print (str);' –

+0

Inoltre per il commento di @ Gene, la pura funzione virtuale deve essere protetta in modo che le classi derivate non amiche possano implementarla. –

+1

@Daniel Trebbien: si potrebbe tranquillamente lasciarlo come privato e sarà ancora implementabile. Ma sono d'accordo che la protezione è probabilmente una buona idea. –

-2

La tecnica che uso è funzionalmente identico a quello che altri hanno detto, eccetto che faccio la funzione di "stampa" virtuale di un sovraccarico di funzione membro dell'operatore >>:

class my_class 
{ 
protected: 
    virtual std::ostream& operator>>(std::ostream& os_) const 
    { 
     // print *this to `os_` 
     return os_; 
    } 

public: 
    friend inline std::ostream& operator<<(std::ostream& os, const my_class& mc) { 
     return (mc >> os); 
    } 
}; 

Questa è l'idea alla base di un modello di utilità da uno dei miei progetti open source. Vedi: https://libnstdcxx.googlecode.com/svn/trunk/doc/html/classnstd_1_1basic__printable.html