Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » virtual friend ostream& operator<<

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
05.12.2004, 21:36 Uhr
~ugh_bough_
Gast


hi.
hab mal eine frage. will mir eine exception klasse machen, um erst mal die grundlagen der vererbung in c++ zu lernen. bis jetzt hab ich das hier

C++:
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Exception
{
        private:
                string _type;
                string _msg;

                static bool     startLog;
                static char*    logFile;

        public:
                Exception(const string& msg, const string& type = ""):
                _type(type + "Exception"),
                _msg(msg)
                {
                        log(*this);
                }

                static void resetLog()
                {
                        ofstream ofs(logFile);
                        ofs.close();
                }

                static void log(Exception& re)
                {
                        if (startLog)
                        {
                                startLog = false;

                                ofstream ofs(logFile);
                                ofs << re << endl;
                                ofs.close();
                        }
                        else
                        {
                                ofstream ofs(logFile, ios::out | ios::app);
                                ofs << re << endl;
                                ofs.close();
                        }
                }

                friend ostream& operator << (ostream& ros, const Exception& re)
                {
                        ros << re._type << ": " << re._msg;
                        return ros;
                }
};

bool    Exception::startLog     = true;
char*   Exception::logFile      = "./exceptions.log";



wenn ich aber nun eine speziellere exception von dieser basisklasse ableite, möchte ich auch mehr info in den stream ausgeben.
dazu muss ich ja den operator<< überschreiben. wenn ich aber diese abgeleitete exception als basis exception behandeln möchte, dann muss die funktion ja virtual sein, damit die überschriebene version dieser "funktion" (nämlich die der abgeleiteten klasse) benutzt wird.

wenn ich aber

C++:
...
                virtual friend ostream& operator << (ostream& ros, const Exception& re)
                {
                        ros << re._type << ": " << re._msg;
                        return ros;
                }
...


versuche, gibt der compiler

Code:
Exception.hpp:49: error: virtual functions cannot be friends
Exception.hpp:49: error: `std::ostream& Exception::operator<<(std::ostream&, const Exception&)' must take exactly one argument
Exception.hpp: In static member function `static void Exception::log(Exception&)':
Exception.hpp:37: error: no match for 'operator<<' in 'ofs << re'


und noch mehr fehlermeldungen aus.

kann mir jemand sagen, was ich falsch mache. könnte dieser jemand auch eine kurze erklärung abgeben, damit ich die hintergründe verstehe. mann will ja nicht dumm bleiben

vielen dank
ugh_bough
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
06.12.2004, 02:42 Uhr
typecast
aka loddab
(Operator)


Ich hab das nur kurz ueberflogen und kann auf die schnelle nur diesen einen Fehler finden, der zu deiner Fehlermeldung passt (allerdings sagt dir ja die Fehlermeldung schon, wo der Fehler liegt )

Also da steht virtual functions cannot be friends.

Der Fehler besteht also darin, dass der Operator virtuell ist.
Ich hab jetzt keine Ahnung, was eine vituelle Funktion sein soll, die nicht in einer Klasse steckt.
Das macht irgendwie keinen Sinn fuer mich (wo keine Klasse, da auch keine Vererbung und damit auch keine daseinsberechtigung fuer eine virtuelle Funktion)

Vielleicht kann da jemand anderes helfen.

Die Problem sollte sich aber dadurch loesen koennen, dass du den Operator nicht virtuell machst.

Ein weiterer Fehler koennte sein (aber da bin ich mir nicht sicher und ich hab keine Zeit es auszuprobieren), dass die Definition des Operators innerhalb der Klasse passiert.
friend Funktionen gehoeren per Definition nicht zu der Klasse und ich bin mir nicht sicher, ob sie innherhalb einer Klassendeklaration definiert werden duerfen.
Aber das probierst du am besten selbst aus...

So , jetzt mal gute Nacht
--
All parts should go together without forcing. ... By all means, do not use a hammer. (IBM maintenance manual, 1925)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
06.12.2004, 06:33 Uhr
~ugh_bough_
Gast


ja wie gesagt, der obere code funktioniert. dort wo die funktion noch nicht virtuell ist.
hmm, vielleicht weiß ja jemand anders noch rat?

auch hat mich irritiert, daß der compiler nun eine andere anzahl von argumenten für den operator will. das ist mir auch schon aufgefallen, als ich versuchte, den operator außerhalb der klasse zu definieren...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
06.12.2004, 06:45 Uhr
virtual
Sexiest Bit alive
(Operator)


Hallo,

friend soll bedeuten, daß die Funktion oder Klasse, die als friend genannt wurde, auf internas (== private Members) zugreifen kann. zB:

C++:
class Geheim {
private:
     char* password;

friend void function1(const Geheim&);
};

void function1(const Geheim& g) {
   std::cout<<g.password<<std::endl; // Geht
}

void function2(const Geheim& g) {
   std::cout<<g.password<<std::endl; // Geht nicht
}


Obiges Beispiel soll das verdeutlichen: function1 ist explizit als Freund der Klasse Geheim aufgeführt und damit berechtigt, die private Member (dh die Attribute und Methoden) der Klasse zu nutzen. function2 ist nicht friend; deshalb würde der Kompiler hier meckern.

Übrigens sind die folgenden beiden Codes identisch (bzw. nahezu identisch, es gibt da Unterschiede, die ich jetzt nicht erwähne, weil zunächst unwichtig):

C++:
class Geheim {
private:
     char* password;

friend void function1(const Geheim&);
};

void function1(const Geheim& g) {
   std::cout<<g.password<<std::endl; // Geht
}


ist das gleiche wie

C++:
class Geheim {
private:
     char* password;
public:
friend void function1(const Geheim& g) {
   std::cout<<g.password<<std::endl; // Geht

};


Das heißt mit anderen Worten: man kann die Frienddeklaration in der Klasse auch gleichzeitig als Definitionsort der Funktion nutzen, eben das, was der Poster in 000 tut.
Nur wie eben gesehen und wie von typecast korrekt bemerkt: friends sind eben Funktionen und können nicht virtuell sein.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
06.12.2004, 10:05 Uhr
~ugh_bough_
Gast


ach so...verstehe.

operator<< ist gar keine klassenfunktion von Exception, sonden eigentlich nur die deklaration einer friend funktion (und außerdem auch gleich noch eine definition)

soso.
also läuft es darauf hinaus, daß man für spezielle ableitungen auch neue operator<< funktionen braucht.

aber wie kann man dann bewerkstelligen, daß man einer operator<< funktion eine Exception übergeben kann, diese aber als Instanz ihrer EIGENTLICHEN Klasse, nämlich einer Unterklasse von Exception, behandelt wird.

danke schonmal
ugh_bough
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
06.12.2004, 10:11 Uhr
~doppler
Gast


Um den Operator << wie gewohnt zu benutzen und zu einem Klassen-member zu machen, must du ihn innerhalb der Klasse ostream überladen, weil operator <<(o,e) das gleiche bedeutet wie o.operator <<(e).

Da das aber nicht geht, musst du eine neue operator-Funktion außerhalb der Klasse definieren. Wenn du das in einer header-Datei machst, muss außerdem ein inline davor, da sonst die Eine-Definition-Regel verletzt wird.

Wie es scheint, erkennt dein Compiler anhand des friend, dass der Operator nicht zur Klasse gehört. Um ein anderes Verhalten für eine abgeleitete Klasse zu bekommen, kannst du einfach eine zweite operator <<-Funktion definieren.

außerhalb der Klasse:

C++:
inline ostream& operator << (ostream& ros, const Exception& re)
                {
                        ros << re._type << ": " << re._msg;
                        return ros;
                }

inline ostream& operator << (ostream& ros, const inherited_Exception& re)
                {
                     //...
                }

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
06.12.2004, 12:32 Uhr
~doppler
Gast


Sorry ~ugh_bough_, hatte die Antwort geschrieben, bevor ich dein posting gelesen habe, deshalb nochmal Antworten auf die schon geklärten Fragen.

Wenn du operator <<(ostream &o, const Exception& re) mit einem Objekt einer abgeleiteten Klasse aufrufst, verlierst du meines Wissens leider die Information, dass es sich um ein Objekt der abgeleiteten Klasse handelt.

Das kann man umgehen, indem man mit operator <<(ostream &o, const Exception* re) arbeitet und in der Definition der Funktion eine virtuelle Funktion von Exception aufruft, die in der abgeleiteten Klasse überschrieben ist. Damit sollte das gewünschte Verhalten eintreten. Leider funktioniert das aber nur mit Zeigern.

Also so ungefähr

C++:
class Exception {
public:
     virtual void do_output() {
          //Exception-Ausgabe
     };
};

class inherited_Exception : public Exception {
public:
      void do_output() {
           //inherited-Ausgabe
     };
};

inline ostream & operator <<(ostream& o, const Exception* e) {
      e->do_output();
};



Dann muss man auch keine eigenen Funktionen für die abgeleiteten Klassen schreiben. Vielleicht geht das ganze sogar mit Referenzen, da bin ich mir aber nicht sicher.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
06.12.2004, 12:41 Uhr
virtual
Sexiest Bit alive
(Operator)


@doppler
Sollte auch mit Referenzen gehen.

letztlich wird bei Deiner Lösung aber der Stream o ignoriert...

Meiner Meinung nach sollte man sovorgehen:


C++:
#include <stdexcept>

class MyException: public std::runtime_error {
   MyException(const char* message, ...)
       :std::runtime_exception(message) {
       ...
   }
};
...

try
{
     ...
}
catch(std::exception& e) {
      std::cerr<<e.what()<<std::endl;
}


Dh std::exception, und damit std::runtime_error stellen bereits eine Methode zur verfügung, die einen Exceptiontext liefert.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
06.12.2004, 17:40 Uhr
~ugh_bough_
Gast


hi. nochmal. so hatte ichs mir im endeffekt auch gedacht. hab jetzt ne (*schäm*) java like funktion toString gemacht. das sollte funktionieren.

@ virtual. cooler tip. ich wollte aber eine eigene exception klasse schreiben, damit ich mal die grundlegende vererbung von c++ ansehen kann.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: