Frage zu C++ Code

Gast #5488892
Lesenswert?

Hallo zusammen, ich habe hier folgenden C++ Code und der tut nicht was 
ich erwarte, vielleicht könnt ihr mir da weiterhelfen:
1
#include "../../std_lib_facilities.h"
2

3
enum class Month { jan = 1, feb, mar, apr, mai, jun, jul, aug, sep, okt, nov, dec };
4

5
class Date {
6
public:
7
  Date(int y, Month m, int d) : y{ yy }, m{ mm }, d{ dd };
8
  
9
  // nonmodifying operations
10
  int day() const { return d; }
11
  Month month() const { return m; }
12
  int year() const { return y; }
13
    
14
private:
15
  int y;
16
  Month m;
17
  int d;    // day
18
};
19

20
ostream& operator<<(ostream& os, const Date& dd)
21
{
22
  return os << '(' << dd.year() << ',' << dd.month() << ',' << dd.day() << ')';
23
}
24

25
int main()
26
{
27
  Date today{ 1978, Month::jun, 25 };
28
  cout << "Today: " << today << endl;
29
  keep_window_open();
30
}


Ich möchte in der main-Funktion mit "cout" das Objekt "today" auf den 
Bildschirm ausgeben, aber ich erhalte folgende Fehlermeldungen:

>> Fehler E0349: Kein "<<"-Operator stimmt mit diesen Operanden überein.

>> Fehler C2679: Binärer Operator "<<": Es konnte kein Operator gefunden werden, 
der einen rechtsseitigen Operanden vom Typ "Month" akzeptiert (oder keine 
geeignete Konvertierung möglich)

Beide Fehler beziehen sich auf die Funktion mit der Operator Überladung 
(ostream& operator<<(ostream& os, const Date& dd).

Was muss ich ändern, damit das Programm in main fehlerfrei ausgeführt 
werden kann?
#5488917
Lesenswert?

commanderKeen schrieb:
>
> Was muss ich ändern, damit das Programm in main fehlerfrei ausgeführt
> werden kann?

einen operator << für das Enum Month anlegen, der dann z.B. den Monat in 
Textform in den Stream schiebt.

Du hast es ja für Date auch hinbekommen ;-)

Oder Date gibt den Monat auch als String aus und operator << für Date 
benutzt diese Methode statt month().
#5489053
Lesenswert?

Z.B. so:
1
class Date {
2
public:
3
  Date(int y, Month m, int d) : y{ yy }, m{ mm }, d{ dd };
4
  
5
  // nonmodifying operations
6
  int day() const { return d; }
7
  Month month() const { return m; }
8
  int year() const { return y; }
9

10
  const char * month_str() {
11
     static const char* months[] = { "Jan", "Feb", "Mar",
12
                                     "Apr", "May", "Jun",
13
                                     "Jul", "Aug", "Sep",
14
                                     "Oct", "Nov", "Dec"
15
                                   };
16
    return months[m-1];
17
  }
18

19
private:
20
  int y;
21
  Month m;
22
  int d;    // day
23
};
24

25
ostream& operator<<(ostream& os, const Date& dd)
26
{
27
  return os << '(' << dd.year() << ',' << dd.month_str() << ',' << dd.day() << ')';
28
}

(Keine Gewähr für Fehlerfreiheit, da nur runtergetippt)
#5489203
Lesenswert?

commanderKeen schrieb:
>>> Fehler C2679: Binärer Operator "<<": Es konnte kein Operator gefunden werden,
> der einen rechtsseitigen Operanden vom Typ "Month" akzeptiert (oder
> keine geeignete Konvertierung möglich)

Weil sich enum class nicht implizit nach int konvertieren lässt. Das ist 
einer der Unterschiede zum klassischen enum.

commanderKeen schrieb:
> Ich möchte in der main-Funktion mit "cout" das Objekt "today" auf den
> Bildschirm ausgeben, aber ich erhalte folgende Fehlermeldungen:

Wie soll es denn ausgegeben werden? Der Monat einfach als Zahl oder als 
Name?

Egon N. schrieb:
> Mir persönlich fehlen ja namespaces und die iostream. Die sind schon
> drin? Bevor ich mir da den Code weiter anschau...

Möglicherweise in dem ominösen:

commanderKeen schrieb:
> #include "../../std_lib_facilities.h"
Gast #5489419
Lesenswert?

Danke für eure Vorschläge, mir ist auch ne Idee gekommen. Wenn ich das 
so mache, bekomme ich keine Fehlermeldung und alles läuft:
1
ostream& operator<<(ostream& os, const Date& dd)
2
{
3
  return os << '(' << dd.year() << ',' << int(dd.month()) << ',' << dd.day() << ')';
4
}

vorher war es so:
1
 ... << dd.month() << ..
jetzt so:
1
 ... << int(dd.month()) << ..

Und das "dd.month" die richtigen Werte bekommt stellt ja mein 
Konstruktor sicher. Ist das eine gute Lösung? Einfach ist sie ja, was 
nicht immer gut sein muss.
Gast #5489484
Lesenswert?

commanderKeen schrieb:
> Ist das eine gute Lösung?

Nein, C-Casts und dann auch noch in der "Funktion-Call" Syntax sind 
unschön. Sicherer und besserer ist ein named cast:
1
return os << '(' << dd.year() << ',' << static_cast<int>(dd.month()) << ',' << dd.day() << ')';
Wenn du es als Text haben willst, dann so wie Carl es schon gezeigt hat.
Gast #5489636
Lesenswert?

Kassowarth von Sondermuehlen schrieb:
> commanderKeen schrieb:
>> : y{ yy }, m{ mm }, d{ dd }
>
> Was ist das für eine seltsame Initialisierung?
> Was sagt der Compiler dazu eigentlich?

Das ist eine Memberinitialisiererliste, in den geschweiften Klammern 
könnte auch Hunz und Kunz drin stehen, das sind die Werte mit denen man 
ein Objekt initialisiert z.B. Date {1999, Month::mar, 12}; 1999 = yy, 
Month::mar = mm usw.

Dr. Sommer schrieb:
> static_cast<int>(dd.month())

Stimmt eine explizite Umwandlung ist besser, danke.


Dr. Sommer schrieb:
> Wenn du es als Text haben willst, dann so wie Carl es schon gezeigt hat.

Ja das habe ich zur Kenntnis genommen, wollte aber nur Zahlenwerte, 
hätte ich dazu schrieben sollen. Danke dir für den Vorschlag Carl.
Gast #5514616
Lesenswert?

Dr. Sommer schrieb:
> Nein, C-Casts und dann auch noch in der "Funktion-Call" Syntax sind unschön. 
Sicherer und besserer ist ein named cast:
1
return os << '(' << dd.year() << ',' << static_cast<int>(dd.month()) << ',' << dd.day() << ')';

Nein, named casts auch explizite Typumwandlung genannt, ist nur dann 
erforderlich wenn man mittels Fehlerbehandlung eine verlustbehaftete 
Umwandlung abfangen möchte.
Gast #5514636
Lesenswert?

guest schrieb:
> Nein, named casts auch explizite Typumwandlung genannt, ist nur dann
> erforderlich

Ich habe nicht gesagt dass sie erforderlich sind. Sie vermeiden aber 
Fehler, weil sie dem Compiler strengere Prüfungen ermöglichen. 
Tatsächlich können klassische C Casts alles was named casts können, und 
sogar ein bisschen mehr - diese Fälle sind aber nur aus Abwärts 
Kompatibilitäts Gründen erlaubt und sind grundsätzlich zu vermeiden.
Gast #5514856
Lesenswert?

Man sollte beides nutzen und wissen wann man es braucht:

Implizite Typumwandlung wenn man bewusst einen Wertverlust in kauf 
nehmen kann/will

Explizite Typumwandlung wenn man einen Werteverlust vermeiden will und 
darüber mittels Fehlerbehandlung informiert werden will.
Gast #5514866
Lesenswert?

guest schrieb:
> Implizite Typumwandlung wenn man bewusst einen Wertverlust in kauf
> nehmen kann/will
>
> Explizite Typumwandlung wenn man einen Werteverlust vermeiden will und
> darüber mittels Fehlerbehandlung informiert werden will.

c-style und "named" casts sind beide explizit. In beiden Fällen muss man 
explizit angeben, dass und wohin gecastet wird. In beiden Fällen kann es 
zu Werteverlust kommen. Und was meinst du mit Fehlerbehandlung? Fehler 
beim Compilieren, Exceptions oder was?
Gast #5514881
Lesenswert?

mh schrieb:
> In beiden Fällen kann es
> zu Werteverlust kommen

Du kannst das "static_cast..." Konstrukt in Verbindung mit Exception 
handling nutzen um eine Meldung zu erhalten wenn ein Verlust beim 
Konvertieren auftritt. Das geht mit C-Style casts nicht.
Gast #5514913
Lesenswert?

guest schrieb:
> mh schrieb:
>> In beiden Fällen kann es
>> zu Werteverlust kommen
>
> Du kannst das "static_cast..." Konstrukt in Verbindung mit Exception
> handling nutzen um eine Meldung zu erhalten wenn ein Verlust beim
> Konvertieren auftritt. Das geht mit C-Style casts nicht.

Und wie geht das? static_cast selbst wirft keine Exception. Ok, wenn die 
selbst implementierte Konvertierungsfunktion oder der Constructor eine 
Exception wird ... aber das würde auch beim c-style Cast passieren.
#5515441
Lesenswert?

guest schrieb:
> Man sollte beides nutzen und wissen wann man es braucht:
>
> Implizite Typumwandlung wenn man bewusst einen Wertverlust in kauf
> nehmen kann/will
>
> Explizite Typumwandlung wenn man einen Werteverlust vermeiden will und
> darüber mittels Fehlerbehandlung informiert werden will.

Ich würde sagen, genau umgekehrt. Compiler warnen, wenn durch eine 
implizite Konvertierung ein Wertverlust eintreten könnte.
Mit einer expliziten Typumwandlungen sage ich dem Compiler dagegen, dass 
ich das genau so will, auch wenn es einen Wertverlust bedeuten könnte -> 
keine Compiler-Warnung mehr.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren