Exception werfen beim Aufruf einer virtuellen Methode
-
Tja, wenn Du uns Deine Probleme nicht mitteilst, wirst Du wohl nie zu einer funktionierenden Lösung kommen (auch wenn es sie gibt, und eigentlich sehr trivial ist sowie hier schonmal gepostet wurde).
-
GPC schrieb:
...Dennoch find ich den Exception Ansatz nicht wirklich toll...
Dem stimme ich uneingeschränkt zu.
blueheart schrieb:
...mein Kopf will irgendwie nicht mehr an eine richtige Lösung glauben....
Das (und GPCs Bauchschmerzen) wird vermutlich daran liegen, dass Du "unsauber designt hast". Wenn B und C von A erben, heißt das, dass sie beide "ein A sind".
Wenn dann A eine virtuelle Funktion f() hat, heißt dass das "jedes A auch f() kann".
Da nun "jedes C ein A ist", und "jedes A f() kann" => "C kann f()".Wenn Du nun zu dem Schluß kommst, C soll "f() nicht können", hast Du irgendwo einen Denkfehler gemacht. Entweder "kann nicht jedes A f()" oder "C ist kein A"....
Denk' Dir das nochmal durch.
Gruß,
Simon2.
-
Wenn in A die Methode pure virtual ist, müsste es doch mit dem Verschieben
der Methode in den private Bereich klappen, oder?
-
phlox81 schrieb:
Wenn in A die Methode pure virtual ist, müsste es doch mit dem Verschieben
der Methode in den private Bereich klappen, oder?Das Problem ist eher, dass wir hier von Laufzeitpolymorphie sprechen. Und der kann man leider weder mit Compilezeit- (und dazu zählt die Zugriffskontrolle via private) noch mit Linkzeit-sicherungsmechanismen (wie einer undefinierten pure virtual function) sinnvoll beikommen.
Erst zur Laufzeit entscheidet sich, ob der Basisklassenpointer auf ein B oder ein C zeigt...Gruß,
Simon2.
-
GPC schrieb:
Simon2 schrieb:
GPC|off schrieb:
...Aber von Basisklassenzeigern sprach bisher auch noch niemand
:pNanana:
ser1al schrieb:
...
[cpp]
...
base* p = new base;
...Oha, richtig. ser1als Code hatte ich nur überflogen.
Grüße
GPC
hehe, eigentli wollte ich da member schrieben

Simon2 schrieb:
GPC schrieb:
...Dennoch find ich den Exception Ansatz nicht wirklich toll...
Dem stimme ich uneingeschränkt zu.
Gruß,
Simon2.
und das habe ich ja auch gesagt, das ich den stil nicht gut finde...dennoch wollte ich ihm sagen das es schon funktioniert!
-
Simon2 schrieb:
phlox81 schrieb:
Wenn in A die Methode pure virtual ist, müsste es doch mit dem Verschieben
der Methode in den private Bereich klappen, oder?Das Problem ist eher, dass wir hier von Laufzeitpolymorphie sprechen. Und der kann man leider weder mit Compilezeit- (und dazu zählt die Zugriffskontrolle via private) noch mit Linkzeit-sicherungsmechanismen (wie einer undefinierten pure virtual function) sinnvoll beikommen.
Erst zur Laufzeit entscheidet sich, ob der Basisklassenpointer auf ein B oder ein C zeigt...Gruß,
Simon2.
hm, stimmt...
Dann bleibt nur die Exception, oder in B eine leere Methode implementieren, der Aufruf tut dann nix.
-
phlox81 schrieb:
...in B eine leere Methode implementieren, der Aufruf tut dann nix.
Ist nicht wirklich besser - nur eine andere Form vom "broken contract"
(dann schon lieber eine exception; da hat der Anwender zwar die AKarte gezogen, aber immerhin merkt irgendjemand, dass unerwünschtes Verhalten vorliegt).Aber wie gesagt: Ich denke, dass hier einfach ein Designfehler vorliegt, den es zu beheben gilt.
Gruß,
Simon2.
-
Wieso nicht einfach in C die Methode Nicht definieren.
Jeder Aufruf würde dann zu einem Linker-Error führen ...
-
Freak_Coder schrieb:
Wieso nicht einfach in C die Methode Nicht definieren.
Jeder Aufruf würde dann zu einem Linker-Error führen ...Wie gesagt: Weils nicht klappt.

Einerseits kann es der Linker gar keinen Fehler feststellen (ein entsprechender Aufruf würde mir A::f() verbunden), andererseits kann der Linker nicht feststellen, was erst zur Laufzeit feststeht.Gruß,
Simon2.
-
Während man halt so mit dem Programm arbeitet, poppt ne MessageBox hoch: "Boink. Der Programmierer hat eine Methode verwendet, die er nicht verwenden darf, ich mach Feierabend." ^^
Hehe ich stell mir das grade mit so einem Programm wie Word oder PaintshopPro vor

-
DEvent schrieb:
Hehe ich stell mir das grade mit so einem Programm wie Word oder PaintshopPro vor

Wäre allemal aufschlussreicher als "OpenOffice.exe hat ein Problem verursacht und muss beendet werden. Möchten Sie einen Problembericht an Microsoft senden?"

-
Simon2 schrieb:
GPC schrieb:
...Dennoch find ich den Exception Ansatz nicht wirklich toll...
Dem stimme ich uneingeschränkt zu.
blueheart schrieb:
...mein Kopf will irgendwie nicht mehr an eine richtige Lösung glauben....
Das (und GPCs Bauchschmerzen) wird vermutlich daran liegen, dass Du "unsauber designt hast". Wenn B und C von A erben, heißt das, dass sie beide "ein A sind".
Wenn dann A eine virtuelle Funktion f() hat, heißt dass das "jedes A auch f() kann".
Da nun "jedes C ein A ist", und "jedes A f() kann" => "C kann f()".Wenn Du nun zu dem Schluß kommst, C soll "f() nicht können", hast Du irgendwo einen Denkfehler gemacht. Entweder "kann nicht jedes A f()" oder "C ist kein A"....
Denk' Dir das nochmal durch.
Gruß,
Simon2.
Auf das Problem stößt man schneller als du denkst.
Schau dir z.B. mal das Kompositum Pattern an.Da sind auch alle Objekte Komponenten....aber Blätter können keine Kinder haben und somit auch keine sinnvolle Implementierung der entsprechenden Methoden bieten.
Somit wäre ja eines der "wichtigsten" Design Patterns ein Designfehler?Gruß Spacelord
-
Spacelord schrieb:
Auf das Problem stößt man schneller als du denkst.
Schau dir z.B. mal das Kompositum Pattern an.Da sind auch alle Objekte Komponenten....aber Blätter können keine Kinder haben und somit auch keine sinnvolle Implementierung der entsprechenden Methoden bieten.
Somit wäre ja eines der "wichtigsten" Design Patterns ein Designfehler?Gruß Spacelord
Nein, die Komposition leitest du von einer Basisklasse ab, welche nur die für Blatt benötigten Methoden besitzt.
Siehe auch http://de.wikipedia.org/wiki/Kompositum_(Entwurfsmuster)
-
Simon2 schrieb:
Aber wie gesagt: Ich denke, dass hier einfach ein Designfehler vorliegt, den es zu beheben gilt.
Das kann man so nicht sehen, dazu müßten wir mehr Informationen haben. Manchmal können eben doch alle As irgendwas. Nur eine Ausnahme gibt es: Cs sind zwar As, aber eine einzige Funktion unterstützen sie doch nicht. Dann lieber sowas, als eine furchtbar komplizierte Lösung, die die Gemeinsamkeiten, die vielleicht doch bestehen verdeckt.
-
Jester schrieb:
...Manchmal können eben doch alle As irgendwas. Nur eine Ausnahme gibt es: Cs sind zwar As, aber eine einzige Funktion unterstützen sie doch nicht....
Dann sind sie eben keine As.
So einfach ist das.Mit Mehrfachvererbung (oder meinetwegen JavaInterfaces) kann man durchaus Teilfunktionalitäten vererben und das ist nicht wirklich komplizierter , dafür aber "entwicklungssicherer" (weiß der Nachfolgeprogrammierer in 2 Jahren wirklich noch, warum da ein throw steht und wer sich alles darauf verlässt ? Oder wie alle möglichen Aufrufer sich darauf verlassen ? ...).
Natürlich will ich niemanden verteufeln oder prinzipiell zu einem schlechten Programmierer erklären, der sowas macht, aber das sehe ich eher als "Zugeständnis an eine schmutzige Praxis" (in der Dinge wie "Terminzwang", "technische Beschränkungen der Entwicklungsumgebung", "idiotische Firmenvorgaben" etc. eine Rolle spielen).
Eines, das man nur machen sollte, wenn man mit dem Rücken zur Wand steht ... und ein Messer am Hals hat ... ein sehr, sehr scharfes Messer.
Gruß,
Simon2.
-
Hm, ich glaube es ist jetzt kein besonders schlimmes Design-Verbrechen. Die Welt hat eben Ecken und Kanten, und das Programm bildet ja nur die Welt ab

Simon2 schrieb:
Eines, das man nur machen sollte, wenn man mit dem Rücken zur Wand steht ... und ein Messer am Hals hat ... ein sehr, sehr scharfes Messer.

Na ja, so schlimm wie Methodenpointer casten, ist's ja jetzt doch net

MfG
GPC
-
GPC schrieb:
Hm, ich glaube es ist jetzt kein besonders schlimmes Design-Verbrechen....
OK, es gibt Schlimmere.
Aber mir ging es hier auch noch um den Zusammenhang im Thread:
Hier entwirft gerade offensichtlich ein noch nicht besonders erfahrener C++-Programmierer (ist nicht böse gemeint, sind wir alle letztlich) ein Programm und ihm kommt zur Lösung seines Problems die "offensichtliche Lösung" in den Sinn.
Ich wollte ihn einfach mal auf eine andere (IMO vielversprechendere) "Lösungsmöglichkeit" hinweisen.
Ob der das tatsächlich macht, bleibt ihm ganz allein überlassen.Gruß,
Simon2.
-
Simon2 schrieb:
Jester schrieb:
...Manchmal können eben doch alle As irgendwas. Nur eine Ausnahme gibt es: Cs sind zwar As, aber eine einzige Funktion unterstützen sie doch nicht....
Dann sind sie eben keine As.
So einfach ist das.Jo, so einfach ist das. Einfach und falsch. Lies doch zum Beispiel mal Multi-Paradigm Design for C++. Stichwort: negative variability. Vielleicht liefert auch google was dazu.
edit:
Beispiel aus dem Buch: eine Message-Klasse. Davon erben unterschiedliches Messages. Messages haben üblicherweise einen body. Nur manche messages sind Ausnahmen, die haben keinen body (es sind ganz wenige und messages sind es trotzdem). Soll jetzt die Basisklasse etwa keine Funktion zum Zugriff aus den body bieten? Willste lieber bei jeder normalen Message nen downcast reinbaun? Also den üblichen Fall verkomplizieren?
-
Jester schrieb:
...Jo, so einfach ist das. Einfach und falsch...
"Für jedes noch so komplizierte Problem gibt es eine Lösung, die einfach, allgemeinverständlich, logisch und falsch ist."
(Prof. H. Lesch)

Wie schon gesagt: Es mag in der Praxis und im Spezialfall die am wenigsten schlechte Lösung sein, aber als "Normalfall" kann ich es trotzdem nicht sehen.
Ich sage mal so: Wenn so etwas in einem Anfängerprogramm auftaucht, gibt es in mindestens 80% der Fälle eine bessere Lösung.
Zu Deinem Fall (Ja, ich kenne das Buch NICHT): D.h. bei den "bodylosen Messages" mußt Du jede "body-bezogene Funktion" auf Dauer pflegen und in allen Zusammenhängen, in denen Du Messages nutzt, daran denken, dass es welche gibt/geben könnte, die keinen haben und entsprechende "Sonderlocken" berücksichtigen.Darin kann ich keinen Vorteil sehen.
Mal abgesehen davon, dass wir hier schlechte Erfahrungen damit gemacht haben, "Messages" zu allzu selbständigen Objekten zu machen, sehe ich nicht, wieso man nicht die Hierarchie entsprechend erweitern sollte auf "BodyLessMessage" und "BodyFullMessage" oder schon die Messageklasse mit der "Optionalität" zu versehen (sprich: eine "virtual bool hasBody() = 0").
In beiden Fällen wäre alles klar.Gruß,
Simon2.
-
Beide Fälle verdecken die eigentliche Gemeinsamkeit und spielen sie in den Hintergrund, obwohl sie sich nur in einer Kleinigkeit unterscheiden.
Es kann in manchen Fällen die beste Lösung sein. So ist das nunmal, auch wenn es vielleicht nicht in ein wunderschönes Weltbild in dem es nur positive Variabilität gibt hineinpaßt. Natürlich ist das kein Normalfall, aber es ist durchaus möglich und dieses absolute "klare Sache, das muß ein Designfehler sein" wollte ich so nicht stehen lassen.
Vielleicht kannst Du James O. Coplien aber auch mal ne eMail schreiben, daß die Lösung so einfach ist und auch fragen, warum er dann ein Buch geschrieben hat in dem sowas behandelt wird.
