Defekt in der Sprache? || Serializable-Interface realisieren
Von: Bodo Thiesen (bothie@gmx.de) [Profil]
Datum: 09.12.2008 04:50
Message-ID: <ghkptk$v0k$00$1@news.t-online.com>
Newsgroup: de.comp.lang.iso-c++
Datum: 09.12.2008 04:50
Message-ID: <ghkptk$v0k$00$1@news.t-online.com>
Newsgroup: de.comp.lang.iso-c++
Hallo LiNG
Vor langer, langer Zeit ist mir folgendes Problem beim Ableiten von
Klassen unter gekommen:
struct Inaccessible { int i; };
struct Accomplice : Inaccessible { int a; };
struct Culprit : Accomplice, Inaccessible { int c; };
int main(int argc, char * argv[]) {
Inaccessible i;
Accomplice a;
Culprit c;
i.i; // ok
a.a; // ok
a.i; // ok
c.c; // ok
c.a; // ok
c.i; // ambiguous <--- ???
}
/*
test.cpp:3: warning: direct base 'Inaccessible' inaccessible in 'Culprit' d
ue to ambiguity
test.cpp: In function 'int main(int, char**)':
test.cpp:15: error: request for member 'i' is ambiguous
test.cpp:1: error: candidates are: int Inaccessible::i
test.cpp:1: error: int Inaccessible::i
*/
Das Problem hierbei ist einfach, daà der Kompiler sich einbildet, nich
t zu
wissen, ob C::I::i oder C::A::I::i gemeint ist. Das hatte ich damals, als
ich Nachforschungen angestellt hatte, notgedrungenerweise geschluckt.
Interessanterweise kann man das ganze auch nicht umgehen indem man das c
nach i castet, kurz, an die direkte i-Basis kommt man GARNICHT mehr dran.
Umgehen kann man das ganze Problem natürlich, indem man eine Hilfsklas
se
um I packt und dann c von h statt von i direkt ableitet. Dann kann man c
nach h casten und von dort aus auf das i zugreifen - das ganze nennt man
dann Workaround.
***
Jetzt bin ich aber auf ein anderes Problem gestoÃen, daà mich an
der
Intelligenz der Macher des C++-Standards zweifeln lassen:
struct Base {
int foo(int a);
};
struct Derived {
int foo(char * a);
};
int main(int argc,char * argv[]) {
Base b;
Derived d;
int i;
char * cp;
b.foo(cp); // fehler -> zurecht
b.foo(i); // ok
d.foo(cp); // pl
d.foo(i); // fehler <--- ???
}
Dieses Verhalten wurde damit begründet, daà der Compiler im aktue
llen
Scope von d eine Funktion foo hat und daher die Suche in diesem Scope
aufhört[1]. Nun gibt es dort aber nur die char * - Version, daher kann
foo(int) nicht aufgelöst werden. Jetzt kann man sich natürlich
st
reiten,
ob die Parameterliste zum Funktionsnamen dazugehören oder nicht, nervig
ist das ganze aber auf jeden Fall.
[1] ganz dumm ist diese Regel auch nicht, nimmt man dieses Beispiel an:
int foo(int a);
class C { int foo(long); int bar() { return foo(1); } };
Soll nun ::foo(int) oder C::foo(long) aufgerufen werden? Allerdings
involviert dieses Beispiel unterschiedliche Scope-Klassen (wenn man
es so bezeichnen will), die Elemente der Basisklassen sollten sich
nach meinem Verständnis so verhalten, als wären sie in der
ak
tuellen
Klasse selbst enthalten.
***
So, nun zum Vorwurf des Defekts: Wenn der aktuelle Skope (Culprit aus dem
ersten Beispiel) die direkte Basisklasse Inaccessible kennt, warum hört
dann dort die Suche nicht auf, wenn ich aber auf Elemente zugreifen will
schon? Denn die Tatsache, daà Inaccessible zweimal als Basis vorkommt,
kann der Compiler ja erst erkennen, wenn er eben NICHT nur die
direkten Basisklassen anschaut, sondern weiter runter wandert.
***
Gut, warum kommt das ganze jetzt wieder hoch?
Ich bin gerade dabei, ein Serialize-Interface für einige Klassen
vorzuschreiben (kurz: es geht um ein Echtzeitstrategiespiel, die Klassen,
die Serialize implementieren müssen sind die, die in den Spielstand
gedumpt werden müssen bzw. die Order-Klassen, die über's
Netzwerk
an die
anderen Spieler transportiert werden müssen - aber das nur, um die
Motivation klarzustellen).
Die Idee war es jetzt, einfach alle Klassen von der abstrakten Klasse
Serialize (besser wäre wohl der Name Serializable, den man ja schon von
Kaffee kennt) abzuleiten. Leider holt mich da das erste in diesem
Post genannte Problem wieder ein: Sobald eine Klasse Serialize
implementiert, können die davon abgeleiteten Klassen nicht mehr direkt
von
dieser Klasse abgeleitet werden. Das hat vor allem aber den Nachteil, daÃ
die serialize-Funktionen mitvererbt werden.
Die Frage, die sich mir jetzt also stellt ist: Wie macht man das am
besten? Oder ist der einzige Weg, das in ISO-C++ zu lösen, indem man
schlicht aufpasst, daà man die virtuellen Funktionen der Serialize-Kla
sse
konsequent überall reimplementiert und dann nur EINMAL von Serialize
abzuleiten?
GruÃ, Bodo
[ Auf dieses Posting antworten ]Antworten
- Stefan Reuther (09.12.2008 18:39)
- Florian Weimer (09.12.2008 20:39)
- Michael Karcher (09.12.2008 18:35)
- Bodo Thiesen (19.12.2008 05:03)
- Rolf Magnus (20.12.2008 11:32)
- Bodo Thiesen (21.12.2008 21:37)
- Stefan Reuther (24.12.2008 13:25)
- Thomas J. Gritzan (09.12.2008 20:52)
- Thomas Richter (09.12.2008 22:24)
- Bodo Thiesen (19.12.2008 05:03)
- Helge Kruse (21.12.2008 10:25)
- Bodo Thiesen (21.12.2008 21:45)
- Stefan Reuther (22.12.2008 16:50)
- Helge Kruse (22.12.2008 20:33)
- Bodo Thiesen (19.12.2008 05:03)
