Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - OOP - verschiedene Objekte in ein Array?


mtin - Mo 12.12.05 17:42
Titel: OOP - verschiedene Objekte in ein Array?
ich hab folgendes Problem, wir haben in der Schule jetzt mit der Objektorientierten Programmierung angefangen und da ein Beispiel in C++ bekommen...ich würde das ganze aber gerne in Delphi schreiben und habe nun Probleme alle Objekte (versch. Objekte -> ein array)

dies sind meine 3 Klassen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
type figurC = class
                 x,y:integer;
                public
                 procedure setXY(ortx,orty:integer);
                 procedure getXY(var ortx:integer;var orty:integer);
                 procedure show;
              end;
     quadratC = class(figurC)
                  laenge:integer;
                 public
                  procedure setlaenge(l:integer);
                  procedure show;virtual;
                end;
     circleC = class(figurC)
                  radius:integer;
                 public
                  procedure setradius(r:integer);
                  procedure show;virtual;
                end;

hab also 2 figuren, quadratc und circlec...
(figurC wird nicht benötigt/gezeichnet, dient nur zur Vererbung von n paar dingen)
Diese wollte ich jetzt beide in einem dynamischen Array unterbringen, so dass ich z.b. um alle Kreise und Quadrate zu zeichnen nur eine for-Schleife brauch die von figuren[0] bis figuren[count(figuren)] figuren[i].show; macht...

Hab also versucht den ganzen Spaß zu schreiben, wie die anderen das in C++ gemacht haben:

figuren:array of figurC;

doch irgendwie geht das in Delphi nciht!!! In C++ konnten die einfach dann hinschreiben:

figuren[0] := QuadratC.Create;

soweit meckert Delphi auch noch nicht, allerdings kann ich jetzt in figuren[0].xxxxxx nicht auf die Quadratspeziefischen Funktionen zugreifen, was in C++ nun aber ging!!!!
mein Infoleherer meinte dann noch ich solle das quadrat erst in einer Variable vom typ QuadratC erstellen, und es erst am Ende mit
figuren[0]:= meinequadratvariable;
reinschreiben, aber das ging genausowenig, und außerdem würde ich ja gerne im Nachhinein auf einzelne Elemente des Arrays zugreifen und die jeweiligen speziefischen Einstellungen vornehmen, je nachdem ob da grad ein Kreis oder ein Quadrat an der Stelle gespeichert ist....

ich hoff ma das das einigermaßen verständlich is :D und das das mit delphi möglich is :?


MrSaint - Mo 12.12.05 17:47

Stichwort: SetLength! Du must in dem Array erst mal Speicher reservieren! ALternativ könntest du auch ein statisches Array machen, etwa so:


Delphi-Quelltext
1:
variable: array [0..9of figurC;                    




MrSaint


Gausi - Mo 12.12.05 17:50

Ins Blaue geraten sollte das hinhauen:

Delphi-Quelltext
1:
(figuren[0as QuadratC).laenge;                    


mtin - Mo 12.12.05 17:54

@MrSaint klar an sowas denkich schon ;)

@Gausi DAS KÖNNTE ES SEIN!!!! jetzt wo dus sagst MUSS es eigentlich so sein :D
ich probiers sofort aus!

EDIT:hm, so ganz geht das noch nicht!!

hier nochmal die Zuweisung, erstmal als extra Varialbe und dann erst in das array geschrieben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
if RadioButton1.checked=true then
begin
  meinQuadrat:=QuadratC.Create;
  meinQuadrat.setlaenge(strtoint(Edit3.text));
  meinQuadrat.setXY(strtoint(Edit1.Text),strtoint(Edit2.Text));
  ListBox1.Items.Add(IntToStr(length(figuren))+'. Quadrat');

  figuren[length(figuren)-1]:=meinQuadrat;

  end;
if RadioButton2.checked=true then
begin
  meinKreis:=circleC.Create;
  meinKreis.setradius(strtoint(Edit3.text));
  meinKreis.setXY(strtoint(Edit1.Text),strtoint(Edit2.Text));
  ListBox1.Items.Add(IntToStr(length(figuren))+'. Kreis');

  figuren[length(figuren)-1]:=meinKreis;
end


doch wie zeige ich die jetzt alle an?
bei dem hier kommen leicht viele Fehlermeldungen:

Delphi-Quelltext
1:
2:
3:
4:
5:
for i:=0 to (length(figuren)-1do
 begin
 (figuren[i] as QuadratC).show;
 (figuren[i] as CircleC).show;
 end;

aber das geht genausowenig (wird gar nix angezeigt)

Delphi-Quelltext
1:
2:
3:
4:
for i:=0 to (length(figuren)-1do
 begin
 figuren[i].show;
 end;


Stefan.Buchholtz - Mo 12.12.05 18:37

Deine Prozedurdeklarationen sind falsch - Funktionen, die man überschreiben können soll, müssen in der Basisklasse mit virtual deklariert werden und in abgeleiteten Klassen als override. So ist es richtig:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
type Tfigur = class  
                 x,y:integer;  
                public  
                 procedure setXY(ortx,orty:integer);  
                 procedure getXY(var ortx:integer;var orty:integer);  
                 procedure show; virtualabstract;
              end;  
     Tquadrat = class(Tfigur)  
                  laenge:integer;  
                 public  
                  procedure setlaenge(l:integer);  
                  procedure show;override;  
                end;  
     Tcircle = class(Tfigur)  
                  radius:integer;  
                 public  
                  procedure setradius(r:integer);  
                  procedure show; override;                
                end;


Der Aufruf von Show geht dann mit


Delphi-Quelltext
1:
figuren[0].Show;                    


und es wird abhängig davon ob es nun ein TCircle oder TQuadrat ist das richtige Show aufgerufen. Ich habe Tfigur.show noch als abstract gekennzeichnet, das bedeutet, dass es in Tfigur keine Implementation davon gibt, sondern erst in abgeleiteten Klassen.

Zugriff auf nicht in der Basisklasse enthaltene Prozeduren funktioniert mit einem Cast:


Delphi-Quelltext
1:
(figur[0as Tquadrat).setlaenge(10);                    


Das musst du so machen, weil SetLaenge in Tfigur nicht enthalten ist.


Delphi-Quelltext
1:
figur[0].setlaenge(10);                    


führt deswegen zu einem Compilerfehler. Das ist meines Wissens aber in C++ genauso.
In Delphi ist es übrigens Konvention, Klassennamen mit einem grossen T zu beginnen, deswegen habe ich das hier mal so gemacht.

Stefan


mtin - Mo 12.12.05 23:03

ok danke, das war schonmal sehr Hilfreich!
und...du glaubst es nich...es funktioniert :D

eine nächste frage wäre: wie finde ich heraus ob nun ein Kreis oder ein Quadrat in figuren[i] ist?
das einzige was mir dazu einfallen würde wäre das ausprobieren und mit try..except den Fehler abfangen...aber gibts da ne schönere Möglichkeit?


Delete - Mo 12.12.05 23:13

Ich werfe mal das Wort Collections in den Raum.

Du sagst OOP und fummelst mit Arrays rum :shock:

Hier gibts was schönes: http://www.delphipraxis.net/topic28945.html

http://www.delphipraxis.net/topic62023_tutorial+zur+dpcollection.html


André


Stefan.Buchholtz - Di 13.12.05 11:13

user profile iconmtin hat folgendes geschrieben:
ok danke, das war schonmal sehr Hilfreich!
und...du glaubst es nich...es funktioniert :D

eine nächste frage wäre: wie finde ich heraus ob nun ein Kreis oder ein Quadrat in figuren[i] ist?
das einzige was mir dazu einfallen würde wäre das ausprobieren und mit try..except den Fehler abfangen...aber gibts da ne schönere Möglichkeit?


Das kannst du mit dem is-Operator machen:


Delphi-Quelltext
1:
2:
3:
4:
if figuren[i] is Tquadrat then
begin
  Tquadrat(figuren[i]).setlaenge(10);
  ...


Stefan


Stefan.Buchholtz - Di 13.12.05 11:22

user profile iconMagicAndre1981 hat folgendes geschrieben:
Ich werfe mal das Wort Collections in den Raum.

Du sagst OOP und fummelst mit Arrays rum :shock:

Hier gibts was schönes: http://www.delphipraxis.net/topic28945.html

http://www.delphipraxis.net/topic62023_tutorial+zur+dpcollection.html


Okay, aber da braucht man wieder extra Bibliotheken, weil Delphi (zumindest Delphi 7, Win32) nicht wirklich gut mit Collections ausgestattet ist. Java oder .NET sind da wesentlich besser gerüstet. Wir haben hier für interne Verwendung auch ein paar Collection-Klassen geschrieben.
Manchmal ist aber ein gutes altes Array auch die beste Lösung - wenn man weiss, wie viele Objekte man hat und nur über Index drauf zugreifen will, ist eine Collection-Klasse nur unnötiger Overhead.

Stefan