![]() |
Constructor in der Vererbung
Hi,
ich habe mir eine Basisklasse erstellt:
Delphi-Quellcode:
Published und Public hab ich hier mal weggelassen.
type
TBefehl = class(TObject) private fGUID: Ansistring; constructor Create; published ... public ... end; Im Constructor Create wird eine GUID erzeugt, die in fGUID gespeichert wird. Jetzt erstelle ich mir noch eine Klasse aus meiner Basisklasse:
Delphi-Quellcode:
Auch hier hab ich mal die Variablen, Properties, Proceduren und co. weggelassen.
type
TECHO = class(TBefehl) private ... published ... public ... end; Grundsätzlich hätt ich jetzt gedacht, meine Klasse TECHO (hat keinen eigenen Constructor) erbt von der TBefehl den Constructor Create, so wie die Klasse TBefehl eben diesen von TObject erbt. Aber, mein Constructor wird nie ausgeführt. Hab ich das falsch verstanden und mache einen Denkfehler? |
AW: Constructor in der Vererbung
Wenn du von ausserhalb deiner Klassenhierarchie TBefehl.Create bzw. TECHO.Create verwendest, dann wird nicht der private Konstruktor der Klasse TBefehl aufgerufen (der ist ja nach aussen auch gar nicht sichtbar), sondern der öffentliche Konstruktor von TObject. Und der macht so ziemlich gar nichts.
Du kannst ja mal probieren, TBefehl.Create zu verwenden (von ausserhalb der Klasse TBefehl). Du müsstest eine Fehlermeldung bekommen. // Edit: Private Konstruktoren machen eigentlich nur Sinn, um von innerhalb derselben Klasse (z.B. in einer Factorymethode) verwendet zu werden. An deiner Stelle würde ich den Konstruktor von TBefehl einfach als public deklarieren und je nachdem auch noch virtuell machen. |
AW: Constructor in der Vererbung
Ist ein privater Konstruktor nicht an sich schon ziemlich sinnentleert?
|
AW: Constructor in der Vererbung
Leider wäre er nur vollkommen sinnentleert wenn Delphi nicht so eine komische Definition von Sichtbarkeiten hätte. "Private" heißt ja nur "Diese Klasse und gleich noch alles in dieser Unit auch". "Strict private" wäre vollkommen sinnentleert. :stupid:
Noch am Rande: Warum ist fGuid ein String und keine TGUID? |
AW: Constructor in der Vererbung
Zitat:
Da TEcho sich in der gleichen Unit befindet, dachte ich, da ich diese aus TBefehl ableite, dass sie auch deren Create verwendet. Die Klasse TBefehl wird in meinem Prog nie direkt erzeugt, sondern dient nur als Basis für anderen Objecte. Aber: Constructor in Public....schon geht's. Gut, dann hab ich das vielleicht nicht ganz richtig verstanden. Wenn ich mein Object TECHO in der gleichen Unit erzeugt hätte, hätte es vielleicht auch so funktioniert. Zitat:
|
AW: Constructor in der Vererbung
Wenn du beide in die gleiche Unit gepackt hast (Igitt!) dann sollte es eigentlich gehen! Kannst du ein reproduzierbares Minimalbeispiel einstellen?
Delphi-Quellcode:
program Project2;
{$APPTYPE CONSOLE} {$R *.res} type TBaseClass = class (*strict*)private constructor Create(); end; TSubClass = class(TBaseClass) // Nichts end; { TBaseClass } constructor TBaseClass.Create(); begin WriteLn('Hallo'); end; begin TSubClass.Create(); ReadLn; end. |
AW: Constructor in der Vererbung
Dein Constructor wird ausgeführt, wenn er an der Stelle des Aufrufs sichtbar ist. (also nur innerhalb der Unit)
PS: in der RTTI gibt es eine Klasse, da wollte Emba unbedingt allen "fremden" den Aufruf des Constructors, bzw. das Erstellen der Klasse verbieten. - Es gibt einen privaten constructor, welcher nur innerhalb der eigenen Unit vom eigenem Code aufgerufen werden kann. - Und es gibt einen public Constructor, in dem nichts Anderes gemacht wird, außer eine Exceptions "nee, DU nicht!" zu werfen. |
AW: Constructor in der Vererbung
Na klar :-)
Unit BABClasses:
Delphi-Quellcode:
Unit Main:
unit BABclasses;
interface uses System.Contnrs, System.Classes, System.SysUtils; type TBefehl = class(TObject) private fGuid: AnsiString; published property Guid: AnsiString read fGuid write fGuid; public constructor Create; end; type TECHO = class(TBefehl) private fText: AnsiString; published property Text: AnsiString read fText write fText; end; implementation constructor TBefehl.Create; var g: TGUID; begin inherited Create; CreateGUID(g); self.fGuid:=GUIDToString(g); end; end.
Delphi-Quellcode:
Ich habs aber mal zusammengekürzt, kann nicht alles hier posten. So aber in etwa. Hier habe ich das Create in Public, und so geht's auch.
unit main;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.Buttons, BABclasses, Vcl.Menus, System.Contnrs; type Tfrm_batchdefinition = class(TForm) lst_test: TListBox; btn_Add: TSpeedButton; procedure btn_AddClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } public BefehlsListe: TObjectList; { Public-Deklarationen } end; var frm_main: Tfrm_main; implementation {$R *.dfm} procedure Tfrm_main.FormCreate(Sender: TObject); begin Befehlsliste:=TObjectList.Create; end; procedure Tfrm_main.FormDestroy(Sender: TObject); begin Befehlsliste.free; end; procedure Tfrm_main.btn_AddClick(Sender: TObject); var echo: TECHO; begin echo:=TECHO.Create; lst_temp.items.add(echo.guid); end; |
AW: Constructor in der Vererbung
Wie wäre es, wenn die TObjectList auch noch auf OwnsObject umgestellt wird?
Oder man verwendet stattdessen eine generische TObjektList<TBefehl>, oder eine TCollection, bzw. eine TQueue<TBefehl> usw., welche sich auch um die Freigabe der Objekte kümmern. Statt die Objekte manuell zu erstellen, kann man der Liste auch Funktionen verpassen, welche diese Instanzen intern erstellen und zu sich hinzufügen. |
AW: Constructor in der Vererbung
Zitat:
Private sollte man grundsätzlich nur Member machen, die nur innerhalb dieser Klasse benutzt werden. |
AW: Constructor in der Vererbung
Nicht ganz. Innerhalb einer Unit ist Private wie Public, weswegen auch das Strict Private erfunden wurde.
|
AW: Constructor in der Vererbung
Zitat:
Man kann das Verhalten von Private innerhalb einer Unit auch als Designfehler betrachten, der aus Kompatibilitätsgründen nicht direkt behoben werden konnte. Die Einführung von Strict Private als echtes Private war sozusagen die Konsequenz. Wenn ich sehe, daß auf Private Member von außerhalb der eigenen Klasse zugegriffen wird, ist das eigentlich ein Fall für ein Refactoring. Leider ist das auch im Delphi-eigenen Source viel zu weit verbreitet. |
AW: Constructor in der Vererbung
Zitat:
![]() In Delphi bleibt einem da leider nichts anderes übrig, als die beteiligten Klassen in dieselbe Unit zu packen und dort auf private oder protected Member zuzugreifen. |
AW: Constructor in der Vererbung
Zitat:
Delphi-Quellcode:
Edit - Anmerkung: Ich habe nur das von der IDE vorgefertigte Projekt ergänzt und gekürzt. Das es als Programm so nicht laufen kann, ist mir klar.
type
TForm1 = class(TForm) protected Procedure ProtectedProc(); end; var Form1: TForm1; implementation Procedure TForm1.ProtectedProc(); begin end; procedure Main(); begin Form1.ProtectedProc(); // kein Fehler !!! end; |
AW: Constructor in der Vererbung
Das stimmt nicht ganz. Abgeleitete Klassen können auf private Felder/Methoden nur dann zugreifen, wenn sie in derselben Unit deklariert sind. Für protected Members gilt das nicht.
|
AW: Constructor in der Vererbung
Dann wären da noch Tricksereien mit Klassenhelfern und Interposer-Klassen (die ja grade wegen dem "oder selbe Unit"-Prinzip funktionieren).
Die Sichtbarkeitsmodifikatoren einmal überarbeiten- Das ist mein #1-Feature was mir in der Sprache Delphi/Object Pascal am meisten fehlt. Bitte gebt mir vernünftige Namespaces und einen Sichtbarkeitsmodifikator der dem "internal" in C# bzw dem "Default" in Java entspricht. Und damit bitte gleich ein
Delphi-Quellcode:
8-)
uses System.Generics.*
C++ hat zwar auch nur public, private und protected aber wenigstens noch vernünftige Namespaces und im Notfall ein "using". In Pascal gewinnt einfach nur der letzte Import- Und man bekommt noch nicht einmal eine Compilerwarnung wenn eine Unit Symbole einer anderen einfach verdeckt. Das finde ich schon ziemlich hart. |
AW: Constructor in der Vererbung
Ich muss das ursprüngliche Thema noch mal aufgreifen, da ich noch ein paar Probleme habe, die ich mir nicht erklären kann.
Hier noch mal meine Klassen:
Delphi-Quellcode:
Die Funktionen dazu
type
TBefehl = class(TObject) private fGuid: AnsiString; fZeilen: Integer; fZeilenText: AnsiString; fFirstRow: Integer; fLastRow: Integer; fElseRow: Integer; FBlockGuid: AnsiString; FIsInBlock: Boolean; FIsInElse: Boolean; published property Zeilen: Integer read fZeilen write fZeilen; property ZeilenText: AnsiString read fZeilenText write fZeilenText; property FirstRow: Integer read fFirstRow write fFirstRow; property LastRow: Integer read fLastRow write fLastRow; property ElseRow: Integer read fElseRow write fElseRow; property IsInBlock: Boolean read FIsInBlock write FIsInBlock; property IsInElse: Boolean read FIsInElse write FIsInElse; property GUID: AnsiString read fGuid write fGuid; property BlockGuid: AnsiString read FBlockGuid write FBlockGuid; public constructor Create; procedure WriteBefehlToStream(Stream: TStream); procedure ReadBefehlFromStream(Stream: TStream); end; type TECHO = class(TBefehl) private fOn: Boolean; fOff: Boolean; fAt: Boolean; fText: AnsiString; procedure SetRow(Row: Integer); function GetRow: Integer; procedure SetIsInBlock(Value: Boolean); function GetIsInBlock: Boolean; procedure SetIsInElse(Value: Boolean); function GetIsInElse: Boolean; procedure SetBlockGuid(Value: Ansistring); function GetBlockGuid: Ansistring; public procedure BuildZeilenText; procedure WriteToStream(Stream: TStream); procedure ReadFromStream(Stream: TStream); published property IsOn: Boolean read fOn write fOn; property IsOff: Boolean read fOff write fOff; property IsAt: Boolean read fAt write fAt; property Text: AnsiString read fText write fText; property Row: Integer read GetRow write SetRow; property localIsInBlock: Boolean read GetIsInBlock write SetIsInBlock; property localIsInElse: Boolean read GetIsInElse write SetIsInElse; property localBlockGuid: AnsiString read GetBlockGuid write SetBlockGuid; end;
Delphi-Quellcode:
in der Formunit geht's dann folgendermaßen:
procedure TECHO.SetRow(Row: Integer);
begin fFirstRow:=Row; fLastRow:=Row; fElseRow:=-1; fIsInBlock:=False; fIsInElse:=False; fBlockGuid:=''; end; function TECHO.GetRow: Integer; begin Result:=fFirstRow; end; procedure TECHO.SetIsInBlock(Value: Boolean); begin self.FIsInBlock:=Value; end; function TECHO.GetIsInBlock: Boolean; begin Result:=Self.FIsInBlock; end; procedure TECHO.SetIsInElse(Value: Boolean); begin self.FIsInElse:=Value; end; function TECHO.GetIsInElse: Boolean; begin Result:=self.FIsInElse; end; procedure TECHO.SetBlockGuid(Value: AnsiString); begin self.FBlockGuid:=Value; end; function TECHO.GetBlockGuid: AnsiString; begin Result:=self.FBlockGuid; end; procedure TECHO.BuildZeilenText; begin if (Self.fOn and not Self.fOff) then Self.ZeilenText:='ECHO On' else if (not Self.fOn and Self.fOff) then Self.ZeilenText:='ECHO Off' else if (not Self.fOn and not Self.fOff) then Self.ZeilenText:='ECHO '+self.fText; if self.fAt then Self.ZeilenText:='@'+Self.ZeilenText; self.Zeilen:=1; end;
Delphi-Quellcode:
BefehlsList ist eine TObjectList.
echo:=TECHO.Create;
echo.IsOn:=frm_echo.rb_echoon.Checked; echo.IsOff:=frm_echo.rb_echooff.Checked; echo.IsAt:=frm_echo.chk_at.Checked; echo.Text:=frm_echo.edt_eigenerText.Text; echo.BuildZeilenText; if (chk_anfuegen.Checked) or (lst_batch.Items.Count=0) then begin BefehlsListe.Add(echo); ActRow:=BefehlsListe.Count-1; end else begin begin echo.localIsInBlock:=InBlock; echo.localIsInElse:=InElse; echo.localBlockGuid:=Blockguid; BefehlsListe.Insert(IndexOfBefehlGuid(BefehlguidListe[ActRow]), echo); Nun mein Problem: Bis zum "BefehlsListe.Insert" funktioniert alles. D.h. alle Properties werden wie gewünscht gesetzt, das habe ich im Debugger kontrolliert. Wenn ich mir nach dem Insert mein Object "echo" im Debugger ansehe, dann die die Properties "IsInBlock, IsInElse und Blockguid" immer auf False bzw '' , egal was ich vorher gesetzt habe. Ich komme aber nicht dahinter, warum das so ist. Interessanterweise ist der Zeilentext, der ja auch in der Klasse TBefehl deklariert ist, noch dem Insert noch vorhanden. Bitte nicht über den Sinn der Funktionen oder Propertynamen diskutieren, ist eh nur ein Spass- und Übungsprojekt. |
AW: Constructor in der Vererbung
Wird vielleicht SetRow aufgerufen?
|
AW: Constructor in der Vererbung
Zitat:
(Typisch Uwe...kurz und knapp und immer auf den Punkt;-) ) Das sucht man Stundenlang, und hat's vor Augen.....(kopfschütteln). Hab schon in den Tisch gebissen, weil ich immer nach einem Fehler in der Definition gesucht habe. Ich mach besser mal Schluss für heute :-D |
AW: Constructor in der Vererbung
Am Rande: Dein BefehlsList ist noch die alte TObjectList und nicht die aus System.Generics.Collections, oder?
Auch: Kannst du nicht im Debugger weiter hineingehen (F7), was darin jetzt mit deinem Objekt angestellt wird? Und: Ich habe jetzt nicht lange darüber gebrütet, aber GUID, Methoden zum Index suchen, usw- Hast du dir mal das TDictionary angeschaut? |
AW: Constructor in der Vererbung
Zitat:
![]() Einfach auf ein Feld setzen, was sich wundersamerweise verändert hat und wuppdi stoppt der Debugger an der Stelle, wo das passiert. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:33 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz