ich hab den Wunsch, Materialien z.B. in OpenGL zu verwenden, OHNE mich um deren Typ oder Ursprung zu kümmern.
Vergleichbares kennt man ja evtl. aus diversen 3D-Programmen wie z.B. 3ds Max. Der Materialeditor dort lässt einen die Art des Materials einstellen und liefert dann an die Render-Engine das Material in einem einheitlichen Format. Meinetwegen als 2D Bitmap. Ich möchte aber wenn ich ein Objekt in OpenGL rendere auch Texturen mit drauf haben. Ich bin aber zu faul, für jeden möglichen Materialtyp (2D-Bitmap, Text, zur Laufzeit erstelltes Bitmap, Video...) immer beim Rendern riesige if-Abfragen oder ähnliches zu machen, da mir das zu viel Arbeit ist.
Ich hab mir gedacht, man könnte das z.B. so lösen:
Code:
TMaterial =class(TObject)
[...](Methoden zum Laden aus einem Stream, Datei etc...)
procedure Apply;virtual;abstract;
end;
T2DTexture =class(TMaterial)
[...](Methoden zum Laden aus einem Stream, Datei etc...)
procedure Apply;
end;
TVideo =class(TMaterial)
[...](Methoden zum Laden aus einem Stream, Datei etc...)
procedure Apply;
end;
[...]
Später im Renderteil eines Objektes wird dann nur noch
Code:
Material.Apply;
aufgerufen und schon wurde das Material aktiviert. Falls es eine normale 2D-Texture war, wird es mit glBindTexture2D gebunden usw...
Ich dachte bisher, man könnte das elegant mit dem Zusatz virtual; abstract; lösen, das scheint aber nicht zu gehen.
Meine Frage(n) an euch:
1. Habt ihr verstanden, was ich meine? 2. Wisst ihr eine Lösung für mein Problem?
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Ja das ist die elegante object orientierte Art solche Problem zu lösen. Du mußt bei den Methoden in den abgeleiteten Klassen aber noch override dahinterschreiben, damit sie die alte Methode auch überschreiben und nicht nur verdecken. Eigentlich müßte es wegen dem vergessenen override auch mehrere Warnungen gegeben haben.
Die Prozeduren und Funktionen der Parent-Klasse (TMaterial) sind ja im Moment mit virtual; abstract; deklariert.
Laut Delphi-Hilfe sind virtuelle Methoden extra dafür da, von einer Child-Klasse überschrieben zu werden.
Mit dem Zusatz abstract; wird dem Compiler noch vermittelt, dass die Methode mit virtual; abstract; in der aktuellen Klasse NICHT implementiert ist. Also erscheint mir ein override bei den abgeleiteten Klassen etwas unnötig. Aber es gab eine ganze Liste an Warnungen. Das stimmt. Und wahrscheinlich ist sogar der Großteil auf ein fehlendes override zurückzuführen...
Worauf ich aber hinaus will ist, dass mir Delphi Laufzeitfehler hinwirft, wenn ich dann eine Methode verwenden möchte.
Beispiel:
Code:
TMaterial =class(TObject)
procedure Apply;virtual;abstract;
end;
T2DTexture =class(TMaterial)
procedure Apply;// Hier soll ein override hin?
end;
implementation
procedure T2DTexture.Apply;
begin
// 2D-Textur binden...
end;
procedure DoSomething;
var
Material: TMaterial;
begin
Material := T2DTexture.Create;
Material.Apply;// Hier kommt ein Laufzeitfehler mit der Meldung \"Abstract Error\"
Material.Free;
end;
Sieht eigentlich logisch aus, Delphi verhält sich, jedenfalls aus meiner Sicht, etwas unlogisch. Wahrscheinlich ist aber, dass ich mich unlogisch verhalte und Delphi alles normal ausführt.
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Es kommt diese Exception weil eine abstrakte Methode(TMaterial.Apply) aufgerufen wurde. Wie schon gesagt, da fehlt das override. Die Klasse T2DTexture hat nämlich erstmal zwei Apply Methoden, die geerbte und die neue. Die Methode T2DTexture.Apply wird ohne zusätzliche Angaben statisch gebunden, ist nicht virtuell und hat mit dem geerbten Apply nichts zu tun. Das ist nicht wie in Java, wo Methoden mit gleichem Namen und gleichen Parametern automatisch überschrieben werden.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Was Lars meint ist folgendes.
Code:
T2DTexture =class(TMaterial)
procedure Apply;override;
end;
Evtl wäre es auch nicht verkehrt wenn du deinen Methoden auch noch eine Sichbarkeit gibst, da sie so immer published sind. An und für sich spricht da nichts gegen nur wenn du Variablen hast auf die nicht jeder zugreifen sollte, dann kannst du es so schlecht verpacken.
Hey, ein fettes Danke!
Das override hat's gebracht!
Ich hab nur angenommen, dass der Compiler anhand der Schlüsselwörter "virtual; abstract;" selber darauf kommt, dass bei zwei vorhandenen Methoden (Apply von TMaterial und Apply von T2DTexture) die Methode gewählöt wird, die keine Exception auslöst, bzw. das Apply von T2DTexture.
Im Nachhinein betrachtet wundert mich auch gar nicht mehr, dass ich die Methode Apply in T2DTexture weglassen konnte, ohne dass der Compiler gemeckert hatte.
@Lossy Ex: Dass Lars das gemeint hat, war mir schon klar (Wie man aus dem geposteten Quelltext schließen konnte), aber mir war noch nicht so ganz klar, dass das geerbte Apply mit dem Apply von T2DTexture nichts zu tun hatte.
Was mir zwar schon früher aufgefallen ist, was ich aber auf eine andere Ursache geschoben hatte, war die Deklaration von Create und Destroy in der Klasse TObject. Die sind ja auch virtuell. Bei denen muss (oder sollte) ja auch override angegeben werden, wenn man eine Klasse davon ableitet und Create und Destroy überschreiben will.
Und das kein Laufzeitfehler kommt, wenn man das override vergisst, führe ich jetzt einfach mal darauf zurück, dass die Methoden Create und Destroy ja schon implementiert sind. Irgendwo in der System.pas bzw. im Delphi-Compiler.
Noch mal Thx, mir ging soeben ein wahres auf. Ihr habt geholfen, eines meiner in ein zu verwandeln...
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Das mit dem override ist wirklich nervig, zumal der das auch noch kompiliert. In C++ wäre das eine Fehlermeldung.
Ach ja und das override nur im interface-Teil ranhängen nicht bei Implementation
Wir sind hier aber nicht in C++... Und der Compiler hat ja auch eine Warnung ausgespuckt. Ich hab sie bloß nicht ernst genommen. Es sind doch erst die Eigenheiten, die einen Compiler menschlich erscheinen lassen . Und die Fehlermeldung kam. Zwar leider erst zur Laufzeit, aber sie kam .
Und das dass override in den interface-Teil reinkommt, ist ja eh klar. Da spuckt dann nämlich der Delphi-Compiler einen Fehler aus...
EDIT:
Zitat:
Ja das ist die elegante object orientierte Art solche Problem zu lösen.
Hey Cool... War mir bis dahin gar nicht so bewusst. Aber wenn du das sagst, muss es einfach stimmen....
Ich hatte einfach mal diese Vision... Methoden von verschiedenen Objekten auf die selbe Art aufrufen zu können. Und hatte gehofft, dass das irgendwie elegant geht. Und, OOP sei Dank, es geht
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Um noch was anzumerken. Falls du nur eine Virtuelle Methode überschreibst solltest du an passender Stelle das inherited nicht vergessen. Speziell beim wieder frei geben wird das lebensnotwendig.
Aber wenn du an deine Problem abstrakt herangehst und dann auch ein entsprechendes Objektmodel aufbaust lässt sich so etwas beliebig erweitern und sehr einfach nutzen. Und es ist schön, dass du selber den Vorteil von OOP erkannt hast. Das zeugt von kreativität und ideenreichtum.
ein fehler hätte aber kommen müssen
wenn die elternklasse abstrakt ist und die kindklasse die abstrakten methoden nicht überschreibt, dann ist die kindklasse auch abstrakt. und abstrakt heißt man darf davon keine instanz anlegen, also hätte beim create-befehl ein fehler kommen müssen
naja und mir sind compile-fehler lieber als welche in der laufzeit^^ aber das is wohl geschmackssache *lol*
MfG Pellaeon
P.S. hab grad keine lust auf groß/klein-schreibung^^
Unter .Net sind die ganzen Klassen dann abstract und man kann keine Instanz anlegen. Beim alten Delphi hat man sich, aus welchen Gründen auch immer, anders entschieden. Ich vermute mal damit man nicht immer alle Methoden überschreiben muß. Es ist ja bei Java und auch bei .Net zulässig, dass z.B. eine Methode eine Exception auslöst, wenn diese Funktion nicht implementiert wird. z.B. bei Add/Remove von Objekten die zwar IList (Java) implementieren, aber read only Listen sind. Eventuell hat man sich dabei etwas ähnliches gedacht, nur das man die nicht unterstützten Methoden nicht selber implementieren muß um die Exception auszulösen.
Soso. Wieder was gelernt.
Hab mich schon immer etwas darüber gewundert, dass man beim Ableiten einer Klasse von TObject den Destructor Destroy mit einem override versehen "muss"/sollte, den Constructor Create jedoch nicht.
@Lossy Ex: Ich find's auch schön, dass ich von selber drauf gekommen bin . Mich freut's generell, wenn etwas überraschenderweise funktioniert .
Ich find OOP so schön, weil es irgendwie recht nah am Leben ist. Es hat eine Art Struktur, Klassen von einander abzuleiten. Auserdem bleibt der Code von den Klassen (die Felder, Methoden, Eigenschaften...) auch wirklich in den Klassen. Wunderbar nach ausen hin abgegrenzt. Vorrausgesetzt, man arbeitet sauber. Und gerade das saubere Programmieren hab ich mir in letzter Zeit verstärkt angewöhnt, weil damit u.a. jene Vorteile verbunden sind und es insgesamt betrachtet den Entwicklungsprozess teilweise stark beschleunigt und v.a. wird der Frustrationsfaktor sehr stark gesenkt, wenn man eigenen Code aus einem anderen Projekt einfach kopieren kann und sofort ohne Änderung woanders weiterverwenden kann. Ich weiß nicht, wie man ohne OOP derart bequem Entwickeln könnte.
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Jo...auch wenn OOP schon verdammt alt ist (60er oder 70er Jahre) kommt es jetzt erst richtig raus. Man kann aber auch ohne Klassen gut arbeiten. Guck dir APIs wie OpenGL an. Da is aber beim schreiben der API viel Disziplin gefragt um nicht doch wieder mit DirtyCoding sich die ganze API zu versaun.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Sa Okt 26, 2002 17:14 Beiträge: 188 Wohnort: Hannover/Lüneburg
Man kann aber auch z.Bsp. sowas wie OpenGL in OOP entwickeln und schreibt dann nur eine Schnittstelle, die über einzelne Funktionen die Funktionen der Klasse aufruft und deren Properties setzt. Der Vorteil der API aus reinen Funktionsaufrufen liegt ja darin, dass man sie aus so ziemlich jeder Programmiersprache heraus aufrufen kann.
_________________ Thunderman
Bei schwierigen Problemen entscheiden wir uns einfach für die richtige Lösung. Klar?
Hat halt alles seine Vor- und Nachteile. Aber mit .Net scheint ja endlich etwas zu existieren, was mehr darauf ausgelegt ist, die ganzen Vorteile in sich zu vereinen. Hoffen wir mal, dass es nicht nur bei Windows als unterstütztem Betriebsystem bleibt, sondern auch die angekündigte OS-Unabhängigkeit, ähnlich wie bei Java, umgesetzt wird. Dann hat man bestimmt eine wunderbare Plattform...
_________________ "Für kein Tier wird so viel gearbeitet wie für die Katz'."
Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.