OOP Fragen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Arthur Dent
Beiträge: 21
Registriert: Mi 15. Feb 2012, 22:17

OOP Fragen

Beitrag von Arthur Dent »

Hallo zusammen!

Ich hab im zusammenhang mit Objektorientierte Progrmierung in Lazarus ein par Grundsatzfragen. Zu meinem Hintergrund: Bin selbst kein Softwareentwickler sondern eher so im Hobbybereich unterwegs. Habe aber Durchaus einge Programmiererfahrung mit Java; C#; sowie Python. Da ich für ein umfangreicheres Vorhaben eine "richtig" kompilierte sprache benötige und mir C/C++ zu unhandlich ist, habe ich mich an die Pascaleinführung aus der Schulzeit erinnert und bin so auf Lazarus gekommen. Da ich OOP im wesentlichen mit Java kennengelernt habe, liegt mein hauptproblem beim Thema Speicherverwaltung. Anbei daher eine kleine Beispielklasse mit 3 fragen und Bitte um Korrektur. Vielen Dank im Voraus!

1.) ist es zwingend nötig einen Destruktor zu implementieren
2.) Muss ich die erstellte Matrix instanz händisch bereinigen; oder wird der Speicher automatisch bereinigt wenn das Vertex-Objekt zerstört wird?
3.)Ich hab im wiki gelesen das man beim überladen von Konstruktoren immer die elternklasse beerben muss: https://de.wikibooks.org/wiki/Programmi ... struktoren
in meinem Fall hab ich das nicht gemacht. Die Klasse macht aber erstmal trotzdem was sie soll. Erzeuge ich hier ungewollte Probleme?

Code: Alles auswählen

 
unit vertex;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, matrix;
 
type
  array3_Double = array[0..2] of double;
 
type
  TVertex = class
  private
    vecData: Tvector4_double;
  public
    procedure convertToDirection();
    procedure convertToPosition();
    function toString(): string; overload;
    constructor create(); overload;
    constructor create(x,y,z: double); overload;
    constructor create(inputArray: array3_Double); overload;
  end;
 
implementation
  // constructors
  constructor TVertex.create();
  begin
   vecData.init_zero();
   self.convertToPosition();
  end;
 
  constructor TVertex.create(x,y,z: double); overload;
  begin
   vecData.init(x,y,z,1);
  end;
 
  constructor TVertex.create(inputArray: array3_Double); overload;
  begin
   vecData.init(inputArray[0],
                inputArray[1],
                inputArray[2],
                1)
  end;
 
  // functionality
  procedure TVertex.convertToDirection();
  begin
    vecData.data[3]:= 0;
  end;
 
  procedure TVertex.convertToPosition();
  begin
    vecData.data[3]:= 1;
  end;
 
  function TVertex.toString(): string; overload;
  begin
   result := '[ ' + floatToStr(vecData.data[0]) + ' ]' + system.LineEnding
           + '[ ' + floatToStr(vecData.data[1]) + ' ]' + system.LineEnding
           + '[ ' + floatToStr(vecData.data[2]) + ' ]' + system.LineEnding
           + '[ ' + floatToStr(vecData.data[3]) + ' ]' + system.LineEnding;
 
  end;
 
end.
 
 

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OOP Fragen

Beitrag von Mathias »

1.) ist es zwingend nötig einen Destruktor zu implementieren

Ein Destructor wird nur benötigt, wen die irgend etwas frei geben muss. Aber ein leere Destructor ist nicht nötig.

Was bei Classen sehr wichtig ist, das dies am Ende frei gegeben werden muss. Bei Java ist dies nicht nötig.

Code: Alles auswählen

var
  MyClass:TObject;
begin
  MyClass := TObject.Create//  Classe erzeugen.
  MyClass.xxxxxx// Mache etwas mit der Classe.
  MyClass.Free// Clase freigeben.
end;


2.) Muss ich die erstellte Matrix instanz händisch bereinigen; oder wird der Speicher automatisch bereinigt wenn das Vertex-Objekt zerstört wird?
Wen Matrix eine dynamische Array ist, wird der Speicher automatisch frei gegeben.


3.)Ich hab im wiki gelesen das man beim überladen von Konstruktoren immer die elternklasse beerben muss:
Ja das ist so, dies muss auch bei Destructor geschehen.

PS: Sehe ich das richtig, du willst eine Vektor/Matrix-Klasse erstellen ?
Wen du so was für OpenGL brauchst, habe ich da schon was fertiges:
- https://github.com/sechshelme/Lazarus-O ... vector.pas
- https://github.com/sechshelme/Lazarus-O ... matrix.pas

Ursprünglich hatte ich die Matrix auch mal als Classe, aber da bin ich auf Type-Helper umgestiegen. Dies ist einfacher in der Handhabung, wen du Matrizen multiplizieren, etc. willst.

Oder hast du die Matrix nur als Übung gewählt ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: OOP Fragen

Beitrag von Warf »

Arthur Dent hat geschrieben:Hallo zusammen!

Ich hab im zusammenhang mit Objektorientierte Progrmierung in Lazarus ein par Grundsatzfragen. Zu meinem Hintergrund: Bin selbst kein Softwareentwickler sondern eher so im Hobbybereich unterwegs. Habe aber Durchaus einge Programmiererfahrung mit Java; C#; sowie Python. Da ich für ein umfangreicheres Vorhaben eine "richtig" kompilierte sprache benötige und mir C/C++ zu unhandlich ist, habe ich mich an die Pascaleinführung aus der Schulzeit erinnert und bin so auf Lazarus gekommen. Da ich OOP im wesentlichen mit Java kennengelernt habe, liegt mein hauptproblem beim Thema Speicherverwaltung. Anbei daher eine kleine Beispielklasse mit 3 fragen und Bitte um Korrektur. Vielen Dank im Voraus!

1.) ist es zwingend nötig einen Destruktor zu implementieren
2.) Muss ich die erstellte Matrix instanz händisch bereinigen; oder wird der Speicher automatisch bereinigt wenn das Vertex-Objekt zerstört wird?
3.)Ich hab im wiki gelesen das man beim überladen von Konstruktoren immer die elternklasse beerben muss: https://de.wikibooks.org/wiki/Programmi ... struktoren
in meinem Fall hab ich das nicht gemacht. Die Klasse macht aber erstmal trotzdem was sie soll. Erzeuge ich hier ungewollte Probleme?


1. Nur wenn deine Klasse irgendwas bereinigen muss. Bereinigen musst du z.B. Speicher den du alloziert hast (z.B. New, GetMem, XXX.Create), Dateien die du offen hast oder auch Objekte aus bibliotheken die deinizialisiert werden müssen. Natürlich brauchst du den Destruktor auch wenn du irgendwas bei der Deinizialisierung machen möchtest (z.B. Logging). Kannst ihn aber sonst problemlos weglassen (auch wenn das in der praxis eher selten ist das man nichts aufräumen muss)
2. Ist es ein Pointer oder ein Memory Block (Grunddatentypen, Statisches Array, Record)? Pointer müssen immer bereinigt werden, grunddatentypen nicht. Dynamische Arrays und Strings sind Referenzgezählt, sind also so lange im speicher bis jedes Objekt das eine referenz darauf hält entfernt wurde.
3. Das musst du nur machen wenn deine Klasse von einer Klasse erbt die nicht TObject ist und selbst einen Constructor überlädt.
Beispiel:

Code: Alles auswählen

type
  Class1 = class
  private
    FSomeRecord: record A,B: Integer; end; // record muss nicht aufgeräumt werden
  end;
 
  Class2 = class (Class1)
  private
    FSL: TStringList;
  public
    constructor Create(FileName: String);
    destructor Destroy; override;
  end;
 
  Class3 = class(Class2)
  public
    constructor Create(FileName: String); override;
    constructor Create;
    // Keine Daten = kein aufräumen
  end;
...
  constructor Class2.Create(FileName: String);
  begin
    FSL := TStringList.Create;
    FSL.LoadFromFile(FileName);
  end;
 
  constructor Class3.Create(FileName: String);
  begin
    WriteLn('Loading File: ', FileName);
    inherited Create(FileName); // Muss parent aufrufen um die datei zu laden
    WriteLn('Successfully loaded');
  end;
 
  constructor Class3.Create;
  begin
    Create('default.file'); // Anderen eigenen Constructor callen der dann inherited callt
  end

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OOP Fragen

Beitrag von Mathias »

@Warf

Es wäre von Vorteil, wen du bei deinem Code aus Classx ein TClassx machen würdest. Ein Type sollte im mit T anfangen.
Das wichtigste hast du vergessen, du solltest noch einen FSL.Free in einen Destructor nehmen.

Dies würde in etwa so aussehen:

Code: Alles auswählen

type
  TMyVater = class(TObject)
  private
    sl: TStringList;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Load(s: string);
  end;
 
  TMyChild = class(TMyVater)
  public
    procedure Add(s: string);
    procedure Show;
  end;
 
constructor TMyVater.Create;
begin
  inherited Create;
  sl := TStringList.Create;
end;
 
destructor TMyVater.Destroy;
begin
  sl.Free;
  inherited Destroy;
end;
 
procedure TMyVater.Load(s: string);
begin
  sl.LoadFromFile(s);
end;
 
procedure TMyChild.Add(s: string);
begin
  sl.Add(s);
end;
 
procedure TMyChild.Show;
begin
  ShowMessage(sl.Text);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  MyClass: TMyChild;
begin
  MyClass := TMyChild.Create;
  MyClass.Load('unit1.pas');
  MyClass.Add('// Ende');
  MyClass.Show;
  MyClass.Free;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Arthur Dent
Beiträge: 21
Registriert: Mi 15. Feb 2012, 22:17

Re: OOP Fragen

Beitrag von Arthur Dent »

@Mathias:
Ich Nutze die von Lazarus mitgelieferte unit matrix. Die Vector und Matrixtypen in diesem Modul sind als "type = object" imlementiert. Soweit ich mich rctig erinner ist das sone Art vorläufer der Klassen, bei dem sich operatoren relativ einfach überladen lassen. Wie auch immer. Die Unit sollte wohl im wesentlichen dazu dienen Transformationsoperationen für die Grafikprogrammierung bereitzustellen. Ich bau mir damit grad nen simplen scene graph, welcher vorübergehend als Darstellungstool für einfache 3D-Daten dienen soll. Dafür reicht es erstmal. Für performantere Probleme würd ich ohnehin auf Professionelle Tools wie ALGLIB oder evtl. sogar MKL ausweichen - das kommt aber erst später im Zusammenhang mit der eigentlichen Programmlogik.
Für die Grafik link ich mir später evtl. irgendwas professionelleres ran sowie opencascade oder so.
https://www.freepascal.org/docs-html/rtl/matrix/index-3.html

Dynamische Arrays und Strings sind Referenzgezählt, sind also so lange im speicher bis jedes Objekt das eine referenz darauf hält entfernt wurde.


Halten die Objekte Referenzen auf die Liste oder umgekehrt?
Ich dachte ein dynamisches Array ist sowas wie ne Liste aus Zeigern auf Objekte, in diesem Fall würde ich den Satz so verstehn das die Liste "sich selbst Löscht" sobald jeder Zeiger auf nil zeigt???
Ist das ungefähr so?

Das musst du nur machen wenn deine Klasse von einer Klasse erbt die nicht TObject ist und selbst einen Constructor überlädt.


heist das nun ich hätte inherited aufrufen müssen? Denn ich hab ja den Konstruktor 3-Fach überladen? Oder erbt eine neue Klasse automatisch von TObject sofern nicht explizit anders angegeben?

@ALL

nur zum Verständnis:
Habe ich es richtig verstanden wenn ich denke dass ein aufruf von inherited einfach sämtlichen code der parent methode ausführt? (Also bei konstruktoren i.d.R. Initialisierungscode)

abschließende Frage:
Die Vectorinstanzen in meiner Klasse sind vom type = object und wurden mit *.init() erzeugt. Sie verfügen über keine .free()-methode? Muss ich die anders loswerden oder gillt das gleiche wie für dynamische arrays, strings...

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: OOP Fragen

Beitrag von Warf »

Nein Objekte in Pascal sind Memoryblöcke die normalerweise auf dem Stack liegen und einen Konstruktor haben der Separat ausgeführt wird. Solange du es nicht mit new erzeugst wird es bereinigt sobald der enthaltene memoryblock (also deine Klasse) entfernt wird.

BeniBela
Beiträge: 308
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: OOP Fragen

Beitrag von BeniBela »

objects sind voll praktisch. Solange man keine Pointer braucht, kann man die ganze Speicherverwaltung, Konstruktor, Destruktor weglassen. Völlig rätselhaft warum Delphi überhaupt class eingeführt hat

Inzwischen kann man für sowas aber auch Typhelper verwenden. Da spart man sich das object und die Klasse und hat nur das Array:



Code: Alles auswählen

 
program Project1;
 
{$mode objfpc}{$H+}
 
{$ModeSwitch typehelpers}
 
uses
  Classes,sysutils;
 
 
type
  TArray3_Double = array[0..2] of double;
 
  TArray3_Double_Helper = type helper for TArray3_Double
    function toString: string;
  end;
 
function TArray3_Double_Helper.toString: string;
begin
   result := '[ ' + floatToStr(self[0]) + ' ]' + system.LineEnding
             + '[ ' + floatToStr(self[1]) + ' ]' + system.LineEnding
             + '[ ' + floatToStr(self[2]) + ' ]' + system.LineEnding
             + '[ ' + floatToStr(self[3]) + ' ]' + system.LineEnding;
 
end;               
 
var a: TArray3_Double;
begin
  a[3] := 7;
  writeln(a.toString);       
end
 


noch praktischer

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OOP Fragen

Beitrag von Mathias »

Die Unit sollte wohl im wesentlichen dazu dienen Transformationsoperationen für die Grafikprogrammierung bereitzustellen.
Für dies ist meine oglMatrix.pas optimiert.

Ich bau mir damit grad nen simplen scene graph, welcher vorübergehend als Darstellungstool für einfache 3D-Daten dienen soll. Dafür reicht es erstmal

Hier sieht man die Verwendung gut, es läuft ohne OpenGL.
https://github.com/sechshelme/Lazarus-O ... no_OpenGL_)

Für performantere Probleme würd ich ohnehin auf Professionelle Tools wie ALGLIB oder evtl. sogar MKL ausweichen - das kommt aber erst später im Zusammenhang mit der eigentlichen Programmlogik.
Da kann ich OpenGL empfehlen, etwas schnelleres wirst du kaum finden.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: OOP Fragen

Beitrag von m.fuchs »

BeniBela hat geschrieben:objects sind voll praktisch. Solange man keine Pointer braucht, kann man die ganze Speicherverwaltung, Konstruktor, Destruktor weglassen. Völlig rätselhaft warum Delphi überhaupt class eingeführt hat

https://de.wikipedia.org/wiki/Dynamisch ... _zum_Stack
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

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

Re: OOP Fragen

Beitrag von kupferstecher »

Warf hat geschrieben:Nein Objekte in Pascal sind Memoryblöcke die normalerweise auf dem Stack liegen [...]


m.fuchs hat geschrieben:
BeniBela hat geschrieben:objects sind voll praktisch. Solange man keine Pointer braucht, kann man die ganze Speicherverwaltung, Konstruktor, Destruktor weglassen. Völlig rätselhaft warum Delphi überhaupt class eingeführt hat

https://de.wikipedia.org/wiki/Dynamisch ... _zum_Stack


Die Aussage mit dem Stack stimmt nicht, oder? Der Speicher sollte entsprechend der Deklaration angelegt werden. Bei globalen Variablen als fester Speicherbereich und nur bei lokalen Variablen in Funktionen/Prozeduren auf dem Stack. Die Dokumentation sagt zwar explizit "auf dem Stack", das scheint mir aber nur eine Vereinfachung zu sein als Gegenstück zum dynamischen Speicher (Heap).

In diesem Sinne: Ich finde Object auch sehr praktisch und zwar zur Strukturierung. Die Alternative ist oft eine Klasse (class) von der es genau eine Instanz gibt, die man aber dynamische erst erzeugen muss (Create). Leider gibt es ein paar Inkompatibilitäten zwischen object und class.

Hier bespielhaft die grundlegende Benutzng:

Code: Alles auswählen

Type TMyclass = class
  ...
  Procedure TuWas;
end;
 
var
  MyClass: TMyClass; //Reserviert Platz in Pointergroesse (4byte bei 32bit-OS) für die gesamte Programmlaufzeit
 
begin
  MyClass:= TMyClass.Create//Speicher wird hier reserviert, Adresse des reservierten Speichers wird in MyClass gespeichert
 
  MyClass.TuWas; //Benutzung erst nach Speicherreservierung (über "Create") möglich
  ...
  MyClass.Free//Speicher wird hier freigegeben
end;



Code: Alles auswählen

Type TMyObject = object
  ...
end;
 
var
  MyObject: TMyObject; //Reserviert Platz in Groesse des gesamten Object für die gesamte Programmlaufzeit.
 
begin
  MyObject.TuWas;   //Kann ohne Weiteres benutzt werden
 
end;

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OOP Fragen

Beitrag von Mathias »

objects sind voll praktisch. Solange man keine Pointer braucht, kann man die ganze Speicherverwaltung, Konstruktor, Destruktor weglassen. Völlig rätselhaft warum Delphi überhaupt class eingeführt hat
Vielleicht, weil man dann keine ^ braucht.
Im Grunde gleichen Pascal-Object den Classen von C++ , man kann sie dynamisch und statisch verwenden.

Code: Alles auswählen

type
  PMyObject = ^TMyObject;
  TMyObject = object
    constructor Init;
    procedure Ausgabe(s: string);
    destructor Done;
  end;
 
var
  staticObj: TMyObject;  // Statisch
  dynObj: PMyObject;     // Dynamisch
 
constructor TMyObject.Init;
begin
  WriteLn('Init');
end;
 
procedure TMyObject.Ausgabe(s: string);
begin
  WriteLn(s);
end;
 
destructor TMyObject.Done;
begin
  WriteLn('Done');
end;
 
begin
  staticObj.Ausgabe('Statisch');
 
  New(dynObj, Init);
  dynObj^.Ausgabe('Dynamisch');
  Dispose(dynObj, Done);
end.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: OOP Fragen

Beitrag von Warf »

BeniBela hat geschrieben:objects sind voll praktisch. Solange man keine Pointer braucht, kann man die ganze Speicherverwaltung, Konstruktor, Destruktor weglassen. Völlig rätselhaft warum Delphi überhaupt class eingeführt hat


Da finde ich C++ echt gut, da wird zusätzlich noch automatisch der Konstruktor und destruktor aufgerufen wenn z.B. der Stackframe erzeugt/bereinigt wird, somit können die objekte Gefahrlos selbst dynamischen speicher verwalten ohne das der Nutzer der objekte an Konstruktor und Destruktor denken muss. Und da das Format standardisiert ist kann man die Objekte sogar problemlos in Bibliotheken packen (was zwischen verschiedenen FPC versionen schon mal in die Hose gehen kann) und in anderen Programmen laden.

Ich fänd es echt genial wen Pascal objekte das auch könnten, zumindest den automatischen Konstruktor und Destruktor.

kupferstecher hat geschrieben:Die Aussage mit dem Stack stimmt nicht, oder? Der Speicher sollte entsprechend der Deklaration angelegt werden. Bei globalen Variablen als fester Speicherbereich und nur bei lokalen Variablen in Funktionen/Prozeduren auf dem Stack. Die Dokumentation sagt zwar explizit "auf dem Stack", das scheint mir aber nur eine Vereinfachung zu sein als Gegenstück zum dynamischen Speicher (Heap).

Stimmt, die Objekte müssen nicht auf dem Stack liegen, das war dumm. Was ich eigentlich sagen wollte ist das Objekte im Memoryframe der Deklaration liegen (also z.B. in einem Record als teil des records, in einer Klasse als teil der Klassendaten, etc.).

Man sagt zu sowas gerne Stackobjekt, kommt glaube ich noch aus der prozedualen Zeit, grade zu zeiten von OOP macht die Bezeichnung aber keinen Sinn mehr. Oftmals hat man ja Heapobjekte hat die Stackobjekte haben, die technisch aber dann ja auch im Heap liegen und da hört die Namensgebung irgendwie auf Sinn zu ergeben.

Mathias hat geschrieben:
objects sind voll praktisch. Solange man keine Pointer braucht, kann man die ganze Speicherverwaltung, Konstruktor, Destruktor weglassen. Völlig rätselhaft warum Delphi überhaupt class eingeführt hat
Vielleicht, weil man dann keine ^ braucht.
Im Grunde gleichen Pascal-Object den Classen von C++ , man kann sie dynamisch und statisch verwenden.


Gibts im fpc nicht nen autoderef compilerswitch mit dem man bei Object Pointern (und record pointern?) das ^ weglassen kann? Ich meine mich da an was zu Erinnern

Arthur Dent
Beiträge: 21
Registriert: Mi 15. Feb 2012, 22:17

Re: OOP Fragen

Beitrag von Arthur Dent »

Oha, Jetz wirds mir langsam zu Krass! Ich glaub ich muss mich mal in Ruhe mit dem Thema Speicherverwaltung in Pascal auseinandersetzen.
Vielen Dank erstmal an alle für die Hilfe.
Für mich ist die Frage ausrechend beantwortet :idea:

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: OOP Fragen

Beitrag von Warf »

Warf hat geschrieben:Gibts im fpc nicht nen autoderef compilerswitch mit dem man bei Object Pointern (und record pointern?) das ^ weglassen kann? Ich meine mich da an was zu Erinnern


Hab es grade schnell ausprobiert, funktioniert wunderbar

Code: Alles auswählen

program Project1;
 
{$mode objfpc}{$H+}
{$ModeSwitch AUTODEREF}
 
type
  PTestObj = ^TTestObj;
  TTestObj = object
    A, B: Integer;
  end;
 
var o: PTestObj;
 
begin
  new(o);
  o.A := 5;
  o.B := 10;
  WriteLn(o.A, o.B);
  dispose(o);
end.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: OOP Fragen

Beitrag von Mathias »

Ich lasse es lieber bei dem ^ .
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten