2010-12-31 21 views
36

Ich brauche einen virtuellen < < Operator. Allerdings, wenn ich versuche zu schreiben: 'Operator < <': nur Elementfunktionen und Basen können virtuell seinOperator << virtuell machen?

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

ich den Compiler-Fehler

Fehler 1 Fehler C2575 erhalten

Wie kann ich diesen Operator virtuell drehen?

Antwort

63

Das Problem mit dieser Konfiguration ist, dass der oben definierte Operator < < eine freie Funktion ist, die nicht virtuell sein kann (sie hat kein Empfängerobjekt). Um die Funktion virtuell zu machen, muss sie als Mitglied einer Klasse definiert werden, was hier problematisch ist, weil, wenn Sie den Operator < < als Mitglied einer Klasse definieren, die Operanden in der falschen Reihenfolge stehen:

bedeutet, dass

MyClass myObject; 
cout << myObject; 

wird nicht kompiliert, sondern

MyClass myObject; 
myObject << cout; 

wird legal.

Um dies zu beheben, können Sie das Fundamental Theorem der Software Engineering anwenden - jedes Problem kann durch Hinzufügen einer anderen Ebene der Indirektion gelöst werden. Anstatt Betreiber machen < < virtuell, sollten Sie erwägen, eine neue virtuelle Funktion in die Klasse, die wie folgt aussieht:

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

Dann definieren Operator < < als

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

diese Weise kann der Bediener < < Die freie Funktion hat die richtige Parameterreihenfolge, aber das Verhalten des Operators < < kann in Unterklassen angepasst werden.

Hoffe, das hilft!

+0

danke es ist sehr hilfreich. Ich dachte über diese Lösung nach, aber ich dachte, dass es vielleicht einen anderen Weg gibt, den ich nicht so einfach für die Implementierung kenne. –

+4

* "jedes Problem kann durch Hinzufügen einer anderen Ebene der Indirektion gelöst werden" * - denken Sie daran, jedes Problem mit Ausnahme des Problems von zu vielen Ebenen der Indirektion;) – Kos

+12

@Kos: Nein, nein. Solange Sie es als "unsigned indirection;" deklariert haben, müssen Sie immer mehr und mehr Indirection hinzufügen und das Problem wird sich lösen, wenn Sie über –

2

Es sieht so aus, als ob Sie wirklich Ausgabefunktionalität für eine Hierarchie von Klassen bereitstellen möchten, und wenn ja, können Sie eine friend operator << bereitstellen, die eine virtual-Funktion aufruft.

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 
    } 
}; 

auch in der detaillierten C++ FAQ

25

Sie Ihre Betreiber definieren < < eine virtuelle Druck Methode aufzurufen:

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

rollen Sie wahrscheinlich bedeutete data.print (str); –

+0

Darüber hinaus Zu @ Genes Kommentar muss die pure virtuelle Funktion geschützt werden, damit nicht von Freunden abgeleitete Klassen sie implementieren können. –

+1

@Daniel Trebbien: Sie könnten es genauso einfach wie privat verlassen und es wird immer noch umsetzbar sein. Aber ich stimme dem zu, ist wahrscheinlich eine gute Idee. –

-2

Die Technik, die ich nutzen, um funktional identisch ist, was andere schon erwähnt haben, mit der Ausnahme, dass ich die virtuelle "Druck" -Funktion zu einer Mitgliedsfunktionsüberlastung des >> Operators mache:

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); 
    } 
}; 

Dies ist die Idee hinter einer Dienstprogrammvorlage aus einem meiner Open-Source-Projekte. Siehe: https://libnstdcxx.googlecode.com/svn/trunk/doc/html/classnstd_1_1basic__printable.html