 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Boris Glawe Guest
|
Posted: Fri Feb 17, 2006 10:06 pm Post subject: this dereferenzieren |
|
|
Hallo,
ich bin's mal wieder mit einem etwas sonderbaren Problem:
Ich habe einen Klasse Date. Wenn ich bei ihr ein Attribut (Tag, Monat, Jahr) mit
setter Methoden aufrufen, prüfen diese Methoden, ob das Datum gültig ist. Intern
wird eine Exception geworfen und auch abgefangen. Dazu habe ich unten meine Frage.
In der privaten Methode void Date::checkValidity() dereferenziere ich this. Der
Typ von this ist erwartungsgemäß "const Date*". Nach dem Dereferenzieren, meint
er aber, dass der Typ von *this eine Instanz von InvalidDateException ist.. Der
Compiler spuckt mir folgende Meldungen aus:
g++ -o test test.cpp ../misc/Date.cpp -O3 -Wall
.../misc/Date.cpp: In member function »void Date::checkValidity()«:
.../misc/Date.cpp:38: Fehler: keine passende Funktion für Aufruf von
»InvalidDateException::InvalidDateException(InvalidDateException)«
.../misc/../exceptions/Exceptions.h:30: Anmerkung: Kandidaten sind:
InvalidDateException::InvalidDateException(Date&)
.../misc/../exceptions/Exceptions.h:27: Anmerkung:
InvalidDateException::InvalidDateException(InvalidDateException&)
.../misc/Date.cpp:38: Fehler: in geworfenem Ausdruck
.../misc/Date.cpp:40: Fehler: keine passende Funktion für Aufruf von
»InvalidDateException::InvalidDateException(InvalidDateException)«
.../misc/../exceptions/Exceptions.h:30: Anmerkung: Kandidaten sind:
InvalidDateException::InvalidDateException(Date&)
.../misc/../exceptions/Exceptions.h:27: Anmerkung:
InvalidDateException::InvalidDateException(InvalidDateException&)
.../misc/Date.cpp:40: Fehler: in geworfenem Ausdruck
.../misc/Date.cpp:42: Fehler: keine passende Funktion für Aufruf von
»InvalidDateException::InvalidDateException(InvalidDateException)«
.../misc/../exceptions/Exceptions.h:30: Anmerkung: Kandidaten sind:
InvalidDateException::InvalidDateException(Date&)
.../misc/../exceptions/Exceptions.h:27: Anmerkung:
InvalidDateException::InvalidDateException(InvalidDateException&)
.../misc/Date.cpp:42: Fehler: in geworfenem Ausdruck
.../misc/Date.cpp:46: Fehler: keine passende Funktion für Aufruf von
»InvalidDateException::InvalidDateException(InvalidDateException)«
.../misc/../exceptions/Exceptions.h:30: Anmerkung: Kandidaten sind:
InvalidDateException::InvalidDateException(Date&)
.../misc/../exceptions/Exceptions.h:27: Anmerkung:
InvalidDateException::InvalidDateException(InvalidDateException&)
.../misc/Date.cpp:46: Fehler: in geworfenem Ausdruck
.../misc/Date.cpp:48: Fehler: keine passende Funktion für Aufruf von
»InvalidDateException::InvalidDateException(InvalidDateException)«
.../misc/../exceptions/Exceptions.h:30: Anmerkung: Kandidaten sind:
InvalidDateException::InvalidDateException(Date&)
.../misc/../exceptions/Exceptions.h:27: Anmerkung:
InvalidDateException::InvalidDateException(InvalidDateException&)
.../misc/Date.cpp:48: Fehler: in geworfenem Ausdruck
.../misc/Date.cpp:51: Fehler: keine passende Funktion für Aufruf von
»InvalidDateException::InvalidDateException(InvalidDateException)«
.../misc/../exceptions/Exceptions.h:30: Anmerkung: Kandidaten sind:
InvalidDateException::InvalidDateException(Date&)
.../misc/../exceptions/Exceptions.h:27: Anmerkung:
InvalidDateException::InvalidDateException(InvalidDateException&)
.../misc/Date.cpp:51: Fehler: in geworfenem Ausdruck
Hier der Quellcode
/****Date.h*******************/
#ifndef DATE_H
#define DATE_H
class Date {
public:
Date();
Date(unsigned int, unsigned int, unsigned int);
Date(Date&);
void setDay(unsigned int);
void setMonth(unsigned int);
void setYear(unsigned int);
unsigned int getDay() {return day;}
unsigned int getMonth() {return month;}
unsigned int getYear() {return year;}
private:
void checkValidity();
unsigned int day;
unsigned int month;
unsigned int year;
};
#endif
/**** Date.cpp *****************************************************/
#include "Date.h"
#include "../exceptions/Exceptions.h"
Date::Date() : day(1), month(1), year(1970){}
/*throws InvalidDateExcption, if date is not valid*/
Date::Date(unsigned int day, unsigned int month, unsigned int year) :
day(day), month(month), year(year)
{
checkValidity();
}
Date::Date(Date& date) :
day(date.getDay()),
month(date.getMonth()),
year(date.getYear())
{}
void Date::checkValidity(){
unsigned int day = getDay();
unsigned int month = getMonth();
// TODO check year's validity (compare with current date, etc)
bool monthIsEven = (month % 2 == 0);
/* HIER WERDEN DIE EXCEPTIONS GEWORFEN UND DER COMPILER ERKENNT DEN FALSCHEN TYP*/
/*Wenn ich lokal eine Instanz von InvalidDateException bilde, die ich dann
werfen, sofern eine der unten
stehenden Bedingungen wahr wird, dann kompiliert alles bestens.*/
if (month <= 7){
if( month == 2 && day > 29)
throw InvalidDateException(*this);
else if (monthIsEven && day > 30)
throw InvalidDateException(*this);
else if (! monthIsEven && day > 31)
throw InvalidDateException(*this);
}
else if (month <=12){
if (monthIsEven && day > 31)
throw InvalidDateException(*this);
else if (!monthIsEven && day > 30)
throw InvalidDateException(*this);
}
else
throw InvalidDateException(*this);
}
void Date::setDay(unsigned int day){
unsigned int backup = getDay();
this->day = day;
try{
checkValidity();
}
catch(InvalidDateException & exc){
this->day = backup;
//throw exc; // TODO raise or not rais, this is the question...
}
}
void Date::setMonth(unsigned int month){
unsigned int backup = getMonth();
this->month = month;
try{
checkValidity();
}
catch(InvalidDateException & exc){
this->month = backup;
}
}
void Date::setYear(unsigned int year){
unsigned int backup = getYear();
this->year = year;
try{
checkValidity();
}
catch(InvalidDateException & exc){
this->year = backup;
}
}
/*** Exceptions.h
*********************************************************************/
/************************************************************************/
#ifndef EXCEPTIONS_H
#define EXCEPTIONS_H
#include <string>
using std::string;
class Exception {
public:
Exception(): message(""){}
Exception(string& message) : message(message) {}
string& getMessage(){return message;}
protected:
void setMessage(string& m){message = m;}
private:
string message;
};
class InvalidDateException : public Exception{
public:
InvalidDateException(Date& date) :
date(date)
{}
Date& getDate(){return date;}
private:
Date date;
};
#endif
Wer kann helfen?
Grüße Boris
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
Boris Glawe Guest
|
Posted: Fri Feb 17, 2006 10:06 pm Post subject: Re: this dereferenzieren |
|
|
P.S. ich weiß, dass man in meinem Fall nicht unbedingt Exceptions braucht.
checkValidity() könnte genauso gut auch einen Erfolgswert zurückliefern. Mir
geht es aber darum zu verstehen, warum das hier nicht funktioniert.
Grüße Boris
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Fri Feb 17, 2006 10:06 pm Post subject: Re: this dereferenzieren |
|
|
Boris Glawe <boris@boris-glawe.de> writes:
| Quote: | Ich habe einen Klasse Date. Wenn ich bei ihr ein Attribut (Tag,
Monat, Jahr) mit setter Methoden aufrufen, prüfen diese Methoden, ob
das Datum gültig ist. Intern wird eine Exception geworfen und auch
abgefangen. Dazu habe ich unten meine Frage.
In der privaten Methode void Date::checkValidity() dereferenziere
ich this. Der Typ von this ist erwartungsgemäß "const Date*".
|
Das wäre der Fall, wenn checkValidity() korrekterweise const
deklariert wäre. Ist sie aber nicht; this ist also vom Typ Date *.
| Quote: | Nach dem Dereferenzieren, meint er aber, dass der Typ von *this eine
Instanz von InvalidDateException ist.
|
Das täuscht.
| Quote: | void Date::checkValidity(){
|
[snip]
| Quote: | throw InvalidDateException(*this);
|
[snip]
Was hier passiert ist folgendes:
Es wird (erfolgreich!) auf dem Stapel ein temporäres
InvalidDateException-Objekt erzeugt, mit dem Konstruktor, welcher als
Argument eine Referenz auf Date nimmt.
Anschliessend wird ein Exception-Objekt an einen speziellen Ort (nicht
auf dem Stapel!) kopiert, so dass anschliessend der Stapel abgerollt
und die darauf angelegten Objekte zerstört werden können.
Dein Problem ist, dass das temporäre InvalidDateException-Objekt nicht
vernünftig kopierbar ist. Der Grund dafür ist die Art und Weise, wie
der Kopierkonstruktor von Date deklariert ist:
Date(Date&);
Besser wäre
Date(Date const &);
.. Beim Kopieren soll ja das Original nicht verändert werden.
Übrigens sollte auch der Parameter des Konstruktors von
InvalidDateException vom Typ Date const & sein; das ist aber im
vorliegenden Code kein Problem.
Und auch die drei get*()-Member von Date sollten const deklariert
sein.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
Boris Glawe Guest
|
Posted: Fri Feb 17, 2006 11:06 pm Post subject: Re: this dereferenzieren |
|
|
| Quote: |
Was hier passiert ist folgendes:
Es wird (erfolgreich!) auf dem Stapel ein temporäres
InvalidDateException-Objekt erzeugt, mit dem Konstruktor, welcher als
Argument eine Referenz auf Date nimmt.
Anschliessend wird ein Exception-Objekt an einen speziellen Ort (nicht
auf dem Stapel!) kopiert, so dass anschliessend der Stapel abgerollt
und die darauf angelegten Objekte zerstört werden können.
Dein Problem ist, dass das temporäre InvalidDateException-Objekt nicht
vernünftig kopierbar ist. Der Grund dafür ist die Art und Weise, wie
der Kopierkonstruktor von Date deklariert ist:
|
Wie kommt dann aber der Compiler darauf, den Konstruktor
InvalidDateException::InvalidDateException(InvalidDateException) aufzurufen?
Wie hast du aus der Fehlermeldung des Compilers diese Ursache abgelesen?
| Quote: | Date(Date&);
Besser wäre
Date(Date const &);
. Beim Kopieren soll ja das Original nicht verändert werden.
Übrigens sollte auch der Parameter des Konstruktors von
InvalidDateException vom Typ Date const & sein; das ist aber im
vorliegenden Code kein Problem.
Und auch die drei get*()-Member von Date sollten const deklariert
sein.
|
Ok, das habe ich jetzt gemacht. Funktioniert auch! Danke!
Jetzt hatte ich noch das Problem, dass wenn ich den Kostruktor als Date(Date
const &) deklariere dass der Code mit folgender Meldung nicht mehr kompilierte:
.../misc/Date.cpp: In copy constructor »Date::Date(const Date&)«:
.../misc/Date.cpp:16: Fehler: Die Übergabe von »const Date« als »this«-Argument
von »unsigned int Date::getDay()« streicht Qualifizierer
.../misc/Date.cpp:17: Fehler: Die Übergabe von »const Date« als »this«-Argument
von »unsigned int Date::getMonth()« streicht Qualifizierer
.../misc/Date.cpp:18: Fehler: Die Übergabe von »const Date« als »this«-Argument
von »unsigned int Date::getYear()« streicht Qualifizierer
Behoben habe ich das, indem ich die Methoden "unsigned int get*()" in "unsigned
int get*() const " umdefiniert habe.
Was aber, wenn diese Methoden nicht const sind, also irgendwelche internen
Zustände verändern (Zugriffszähler, etc)? Soweit ich weiß, kann man solche
Methoden dann nicht mehr als const deklarieren!?
Grüße Boris
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Sat Feb 18, 2006 11:06 am Post subject: Re: this dereferenzieren |
|
|
Boris Glawe wrote:
| Quote: | Was hier passiert ist folgendes:
Es wird (erfolgreich!) auf dem Stapel ein temporäres
InvalidDateException-Objekt erzeugt, mit dem Konstruktor, welcher als
Argument eine Referenz auf Date nimmt.
Anschliessend wird ein Exception-Objekt an einen speziellen Ort (nicht
auf dem Stapel!) kopiert, so dass anschliessend der Stapel abgerollt
und die darauf angelegten Objekte zerstört werden können.
Dein Problem ist, dass das temporäre InvalidDateException-Objekt nicht
vernünftig kopierbar ist. Der Grund dafür ist die Art und Weise, wie
der Kopierkonstruktor von Date deklariert ist:
Wie kommt dann aber der Compiler darauf, den Konstruktor
InvalidDateException::InvalidDateException(InvalidDateException)
aufzurufen?
|
Weil er nach einem Kopierkonstruktor für InvalidDateException sucht. Dein
InvalidDateException-Objekt enthält aber ein Date-Objekt, das dann
ebenfalls mitkopiert werden muß. Da der Kopierkonstruktor von Date aber
angeblich das Original modifiziert (Der Parameter ist nicht const),
generiert der Compiler für InvalidDateException ebenfalls einen, dessen
Parameter nicht const ist. Mit dem kann der Compiler aber nichts anfangen,
da du in der throw-Anweisung ein Temporary kopieren willst, und
nicht-const-Referenzen auf Tempoaraies sind in C++ nicht erlaubt.
| Quote: | Wie hast du aus der Fehlermeldung des Compilers diese Ursache
abgelesen?
|
Ist wohl auch ein wenig Erfahrung dabei.
Hellhörig macht aber sowas wie:
InvalidDateException::InvalidDateException(InvalidDateException&)
.../misc/Date.cpp:51: Fehler: in geworfenem Ausdruck
Also ein Kopierkonstruktor, der eine nicht-const-Referenz will.
| Quote: | Date(Date&);
Besser wäre
Date(Date const &);
. Beim Kopieren soll ja das Original nicht verändert werden.
Übrigens sollte auch der Parameter des Konstruktors von
InvalidDateException vom Typ Date const & sein; das ist aber im
vorliegenden Code kein Problem.
Und auch die drei get*()-Member von Date sollten const deklariert
sein.
Ok, das habe ich jetzt gemacht. Funktioniert auch! Danke!
Jetzt hatte ich noch das Problem, dass wenn ich den Kostruktor als
Date(Date const &) deklariere dass der Code mit folgender Meldung nicht
mehr kompilierte:
../misc/Date.cpp: In copy constructor »Date::Date(const Date&)«:
../misc/Date.cpp:16: Fehler: Die Übergabe von »const Date« als
»this«-Argument von »unsigned int Date::getDay()« streicht Qualifizierer
../misc/Date.cpp:17: Fehler: Die Übergabe von »const Date« als
»this«-Argument von »unsigned int Date::getMonth()« streicht Qualifizierer
../misc/Date.cpp:18: Fehler: Die Übergabe von »const Date« als
»this«-Argument von »unsigned int Date::getYear()« streicht Qualifizierer
Behoben habe ich das, indem ich die Methoden "unsigned int get*()" in
"unsigned int get*() const " umdefiniert habe.
|
Genau das hat Thomas doch oben vorgeschlagen.
-> >> Und auch die drei get*()-Member von Date sollten const deklariert
| Quote: | sein.
Was aber, wenn diese Methoden nicht const sind, also irgendwelche internen
Zustände verändern (Zugriffszähler, etc)? Soweit ich weiß, kann man solche
Methoden dann nicht mehr als const deklarieren!?
|
Kommt drauf an. Wenn das Objekt sich von außen gesehen eigentlich nicht
ändert (wie z.B. beim Zugriffszähler, einem Cache oder sowas), dann kann
man die entsprechenden Member mutable definieren. In diesem Fall lässt der
Compiler eine Änderung auch aus const-Memberfunktionen heraus zu.
Wenn sich das Objekt von außen gesehen ändert, ist halt die Frage, ob du die
entsprechenden Memberfunktionen wirklich im Kopierkonstruktor aufrufen
willst. Wenn ja, dann kannst du seinen Parameter nur nicht-const machen und
mußt mit den Einschränkungen leben.
PS: Ich finde es unschön, daß deine Exception ein Date mit sich rumträgt,
das eigentlich invalid ist. Besser wäre es, wenn so ein Date-Objekt
grundsätzlich nicht existieren könnte.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Sat Feb 18, 2006 11:06 am Post subject: Re: this dereferenzieren |
|
|
Boris Glawe <boris@boris-glawe.de> writes:
| Quote: | Anschliessend wird ein Exception-Objekt an einen speziellen Ort
|
Das war wohl nicht so klar in meinem Ausführungen. Anschliessend wird
*das* Exception-Objekt wäre besser gewesen.
| Quote: | (nicht auf dem Stapel!) kopiert, so dass anschliessend der Stapel
abgerollt und die darauf angelegten Objekte zerstört werden können.
Dein Problem ist, dass das temporäre InvalidDateException-Objekt
nicht vernünftig kopierbar ist. Der Grund dafür ist die Art und
Weise, wie der Kopierkonstruktor von Date deklariert ist:
Wie kommt dann aber der Compiler darauf, den Konstruktor
InvalidDateException::InvalidDateException(InvalidDateException)
aufzurufen?
|
Das ist eine mögliche Form des Kopierkonstruktors; er soll verwendet
werden, um das temporäre Exception-Objekt an den speziellen Ort zu
kopieren.
| Quote: | Wie hast du aus der Fehlermeldung des Compilers diese Ursache
abgelesen?
|
Gar nicht. Ich habe Deine Interpretation gelesen, für falsch gehalten
und nach einer besseren gesucht. Schon vorher war mir aufgefallen,
dass die const-Deklarationen fehlen, und irgendwann kam ich auf die
Idee, die beiden Dinge in einen logischen Zusammenhang zu bringen.
| Quote: | Jetzt hatte ich noch das Problem, dass wenn ich den Kostruktor als
Date(Date const &) deklariere dass der Code mit folgender Meldung
nicht mehr kompilierte:
../misc/Date.cpp: In copy constructor »Date::Date(const Date&)«:
../misc/Date.cpp:16: Fehler: Die Übergabe von »const Date« als
»this«-Argument von »unsigned int Date::getDay()« streicht
Qualifizierer
../misc/Date.cpp:17: Fehler: Die Übergabe von »const Date« als
»this«-Argument von »unsigned int Date::getMonth()« streicht
Qualifizierer
../misc/Date.cpp:18: Fehler: Die Übergabe von »const Date« als
»this«-Argument von »unsigned int Date::getYear()« streicht
Qualifizierer
Behoben habe ich das, indem ich die Methoden "unsigned int get*()" in
"unsigned int get*() const " umdefiniert habe.
Was aber, wenn diese Methoden nicht const sind, also irgendwelche
internen Zustände verändern (Zugriffszähler, etc)? Soweit ich weiß,
kann man solche Methoden dann nicht mehr als const deklarieren!?
|
Der Kopierkonstruktor darf ja auf die Datenmembers des Originals
direkt zugreifen:
Date::Date(Date const &d)
: day(d.day)
, month(d.month)
, year(d.year)
{
}
Abgesehen davon sieht dieser Kopierkonstruktor jetzt exakt so aus, wie
ihn der Compiler generieren würde, wenn Du ihn nicht
deklariertest. Ich würde deshalb einfach Deklaration und Definition
des Kopierkonstruktors löschen.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|