[Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

[Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von mulcheo »

Hallo Forum,

womöglich meine dämlichste Frage bislang, aber ich finde einfach kein to-do dafür und glaube, dass ich etwas übersehe...
Wenn ich mit Komponenten wie TMemo arbeite, habe ich ja die nette Punkt-Unterpunkt-Struktur, also etwa

Code: Alles auswählen

Form1.Memo1
Form1.Memo1.Lines
Form1.Memo1.Lines.Add
Form1.Memo1.Lines.Indexof
Form1.Memo1.Lines.Slice
usw. usw.

Ich habe nun meine eigene Klasse, in der Speicherroutinen auf verschiedene records oder andere Klassen definiert werden ... in meinem code steht bislang:

Code: Alles auswählen

TSyntax = class
    Ding1: array of TD1;
    Ding2: array of TD2;
    Ding3: array of TD3;
    [...]

    procedure Add_Ding1(...);
    procedure Add_Ding2(...);
    procedure Add_Ding3(...);
    procedure Remove_Ding1(...);
    procedure Remove_Ding2(...);
    procedure Remove_Ding3(...);
    [...]
... der Aufruf wäre dann Syntax.Add_Ding1 oder Syntax.Add_Ding2 usw.... und nun *Trommelwirbel* meine Frage: wie kann ich stattdessen Syntax.Add.Ding1 / Syntax.Add.Ding2 Strukturen erzeugen. Nach meinem Verständnis, müsste ich eine zweite Klasse (Tadd) dort einbinden, die dann die proceduren bereitstellt, also in etwa:

Code: Alles auswählen

TAdd = class
   procedure Ding1(...);
   procedure Ding2(...);
   procedure Ding3(...);
end;

TSyntax = class
   Add: TAdd;
   [...]
end;    
Aber ist das wirklich der übliche Weg? Und wie sieht es denn dann mit dem Erzeugen der Unterklasse aus, konkret: wieso bekomme ich keine AV (gerade getestet), wenn ich nirgends := Tadd.create im code habe obohl mir sowas sonst immer um die Ohren fliegt?

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 170
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von Jorg3000 »

Hi!
Entweder

Code: Alles auswählen

Syntax.Ding1[Index].IrgendwasVonTD1
oder du machst aus der procedure Add_Ding1() eine Funktion mit Result vom vom Typ TD1

Code: Alles auswählen

function Add_Ding1(...): TD1;
d.h. du übergibst das erzeugte Ding1 als Result, dann kannst du es weiterverwenden

Code: Alles auswählen

Syntax.Add_Ding1(...).IrgendwasVonTD1;
Grüße, Jörg

mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von mulcheo »

aber ich möchte ja gerade von Add_Ding1 weg und hin zu Add.Ding1 .... d.h. in meiner Klasse soll es die Routinegruppen 'add', 'remove' 'speichern', 'laden' etc. etc. geben, die dann auf der 'nächsten Ebene' auf die verschiedenen Objekte, also Ding1 bis Ding99 angewendet werden. Mir geht es da tatsächlich um diese Mehr-Ebenen-Struktur, wie sie beispielsweise für canvas zu finden ist. Es gibt ja bspw. Canvas.Brush und dann mit 'dem nächsten Punkt' alles mögliche, was man damit so machen kann, also .Color, .Style etc. etc. und dann noch Canvas.Font und auf der nächsten Ebene alles, was die Font betrifft, etwa .charset, .height usw.. Dieses Ebene.Ebene.Ebene System will ich auch umsetzen, bin aber irgendwie betriebsblind und weiß einfach nicht, was der klassische Weg wäre - also im interfaceteil...

vielleicht steckt das schon in deiner Antwort drin, aber ich kann's nicht ganz rauslesen

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 170
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von Jorg3000 »

Wenn sich die Parameter deiner Add-Prozeduren unterscheiden, kannst du folgendes machen

Code: Alles auswählen

function Add(...Ding1-Parameter...): TD1;  overload;
function Add(...Ding2-Parameter...): TD2;  overload;

mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von mulcheo »

also die Parameter unterscheiden sich tatsächlich nicht; das sind primär pointer und ein paar Indexvariablen ABER je nachdem, ob die auf Ding1 oder Ding2 angewendet werden, unterscheidet sich dann teils erheblich, was die Prozedur macht.
So wie ich deinen Vorschlag verstehe, gibt die Funktion dann ein neues Objekt vom Typ TDingxy aus. Das ist aber (in Teilen) garnicht mein Szenario. Bei 'speichern' und 'laden' geht es beispielsweise nur darum, irgendwas mit einer typisierten Datei zu machen - 'add' hingegen würde in der Klasse TDingxy ein dynamisches array erweitert, oder auch nicht, je nach Parameter ...

Was ich suche ist tatsächlich nur ein Schema dafür, wie ich die Unterebenen, die ich möchte, im Interface definiere...

um mal ein anderes Beispiel zu nehmen: ich kann ja in einem Programm diverse Variablen haben wie

Code: Alles auswählen

var
  Auto_Breite: integer;
  Auto_Gewicht: integer;
  Auto_Sitzzahl: byte;
  Auto_baujahr: word;
  
  Bus_Länge: integer;
  Bus_Gewicht: integer;
  [...]
und dann halt noch ne ganze Menge weiteren Kram... dann maht es doch Sinn ein record oder eine Klasse zwischenzuschieben, um Strukturen zu schaffen, also

Code: Alles auswählen

type
  TAuto = record
    Breite: integer;
    Gewicht: integer;
    Sitzzahl: byte;
  end; 
  [...]
dann habe ich im Quellcode dann statt Auto_Gewicht:=2000; Auto.Gewicht:=2000; ... und genau das will ich halt mit Prozeduren und Funktionen machen, statt mit Variablen. Meine bisherige Idee ist, eine neue Klasse ohne properties einzuschieben (wie im ersten Post, letztes codebeispiel) aber ich weiß nicht, ob das der klassische Weg dafür ist und verstehe noch nicht ganz, warum ich die neue Klasse in diesem Fall nicht mit .Create erzeugen muss (vermutlich fällt mir hier mein mangelndes Verständnis von Klasse vs. Instanz auf die Füße).
Zuletzt geändert von mulcheo am Do 3. Feb 2022, 11:59, insgesamt 1-mal geändert.

Benutzeravatar
kupferstecher
Beiträge: 422
Registriert: Do 17. Nov 2016, 11:52

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von kupferstecher »

mulcheo hat geschrieben:
Mi 2. Feb 2022, 21:47
Nach meinem Verständnis, müsste ich eine zweite Klasse (Tadd) dort einbinden, die dann die proceduren bereitstellt, also in etwa:
Ja, stimmt.
Aber ist das wirklich der übliche Weg? Und wie sieht es denn dann mit dem Erzeugen der Unterklasse aus, konkret: wieso bekomme ich keine AV (gerade getestet), wenn ich nirgends := Tadd.create im code habe obohl mir sowas sonst immer um die Ohren fliegt?
Die Unterklasse (Vorsicht mit dem Begriff) erzeugst du im Konstruktor der einbindenden Klasse.

Also

Code: Alles auswählen

Type TFoo = class
   public
     Add: TAdd;
  public
    Constructor Create;
    Destructor Destroy; override; 
end;

Type TAdd = class
  [...]
end;

IMPLEMENTATION

Constructor TFoo.Create;
begin
  Add:= TAdd.Create;
end;

Destructor TFoo.Destroy
begin
  Add.Free;
end;
wieso bekomme ich keine AV
Adult videos? ~
Vermutlich hat deine Klasse TAdd noch keine Variablen, auf die du zugreifst. Dadurch kommt es dann auch noch zu keinem Zugriff (Access), also auch zu keiner Access Violation.
Aber ist das wirklich der übliche Weg?
Man sollte m.E. so Konstrukte nicht aus optischen Gründen machen, sondern um eine wirkliche Abstraktion einzuführen. Nimmt man das Canvas-Beispiel, dort ist wirklich das Canvas-Datenfeld im Objekt hinterlegt oder die Klasse dient als Wrapper für eine Struktur an anderer Stelle. Aber man sollte keinen Aufwärtswrapper implementieren. D.h. TAdd sollte kein Wrapper für Daten in TFoo sein.

mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von mulcheo »

okay Danke, das leuchtet ein. Ich habe im Hintergrund etwas experimentiert und verstehe die Mechanik zunehmend. Dann muss ich wohl bald meine eigenen Konstruktoren schreiben. Bislang habe ich mich immer auf die out-of-the-box-Lösung verlassen und einfach .Create verwendet.

Benutzeravatar
kupferstecher
Beiträge: 422
Registriert: Do 17. Nov 2016, 11:52

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von kupferstecher »

mulcheo hat geschrieben:
Do 3. Feb 2022, 11:56
also die Parameter unterscheiden sich tatsächlich nicht; das sind primär pointer und ein paar Indexvariablen ABER je nachdem, ob die auf Ding1 oder Ding2 angewendet werden, unterscheidet sich dann teils erheblich, was die Prozedur macht.
[...]
Bei 'speichern' und 'laden' geht es beispielsweise nur darum, irgendwas mit einer typisierten Datei zu machen - 'add' hingegen würde in der Klasse TDingxy [...]
Ich glaube was du suchst ist Verebung mit gemeinsamer Basisklasse.
In der Basisklasse werden die Funktionen definiert und in den abgeleiteten Klassen dann überschrieben.

Statt
Kontainerklasse.Add.Ding1('blau');
hast du dann
Ding1.Farbe:= 'blau';
Kontainerklasse.Add(Ding1);

mulcheo
Beiträge: 57
Registriert: Do 1. Aug 2013, 15:11

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von mulcheo »

kupferstecher hat geschrieben:
Do 3. Feb 2022, 12:13
Ich glaube was du suchst ist Verebung mit gemeinsamer Basisklasse.
In der Basisklasse werden die Funktionen definiert und in den abgeleiteten Klassen dann überschrieben.
langfristig wird's wohl so kommen. Im Moment bin ich noch auf der Vorstufe 'Punktmechanik verstehen und replizieren' :D

wennerer
Beiträge: 524
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: [Ebene1].[Ebene2].[Ebene3]-Befehle für eigene Klasse

Beitrag von wennerer »

Hallo mulcheo,
ich kann dir diesen Artikel von Michael Puff empfehlen:
http://michael-puff.de/Programmierung/D ... Delphi.pdf

Mir hat er jedenfalls sehr geholfen.

Viele Grüße
Bernd

Antworten