[delphi] Default constructor verbergen met overloads

Pagina: 1
Acties:

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
De titel is niet duidelijk, maar het komst het dichtst bij wat ik wil bereiken:
Ik heb een class gemaakt met een aantal constructors erin, die allemaal overloaded zijn. Al die constructors hebben een aantal parameters. Mijn class is nergens van afgeleid, en dus wordt de standaard TObject ancestor gebruikt.

In TObject zit echter ook een constructor (die redelijk leeg is), en die public is. Dat houdt dus in dat in onderstaande voorbeeldje, TMyClass ook gemaakt kan worden met TMyClass.Create; maar dat zou hopeloos mis gaan.
Delphi:
1
2
3
4
5
type
  TMyClass = class
    constructor Create(Names: TStringList); overload;
    constructor Create(const Name: string); overload;
  end;
Ik wil dus de Create zonder parameters verbergen bij de aanroep. Maar hoe?

Ik heb geprobeerd em te her-declareren in een private-sectie. Gevolg: hij blijft public. Ik heb geprobeerd een van de twee constructor niet-overloaded te maken. Gevolg: compiler-error.

Enige uitweg die ik zie is de Create zonder parameters in vredesnaam maar te implementeren en een exception erin te zetten ofzo. Maar dat is wel heel vies, IMO.

日本!🎌


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Hmm nu ken ik Delphi niet echt, maar C++ maakt alleen een default constructor aan bij gebrek aan andere constructors. Weet je wel zeker dat je een default constructor cadeau krijgt als je anderen definieert? :?

Professionele website nodig?


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Dat doet Delphi ook. Zodra je een constructor aanmaakt in de afgeleide geldt de default constructor niet meer. Maar zodra je overload gebruikt weer wel, want dan is Create gewoon een van de geoverloade methods. Ik ben bang dat je voor de volgende constructie moet gaan:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
type
  TTest = class(TObject)
  private
  public
    constructor Create; reintroduce; overload;
    constructor Create(blabla: String); overload;
    constructor Create(blabla: Integer); overload;
  end;


implementation

uses
  SysUtils;

{ TTest }

constructor TTest.Create(blabla: String);
begin
  inherited Create;
end;

constructor TTest.Create(blabla: Integer);
begin
  inherited Create;
end;

constructor TTest.Create;
begin
  raise Exception.Create('Niet doen aub');
end;

We adore chaos because we like to restore order - M.C. Escher


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 20-05 14:02

Tomatoman

Fulltime prutser

Een static method (die dus niet virtual of dynamic is) kun je niet verbergen door hem te overloaden. Wat je wil kunt doen is hem opnieuw introduceren met de reintroduce directive. Dat voorkomt waarschuwing van de compiler dat je een al bestaande methodnaam gebruikt.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
type
{ static constructors }

  TClass1 = class(TObject)
    constructor Create; 
  end;

  TClass2 = class(TClass1)
    constructor Create(Names: TStrings); reintroduce; 
  end;

  TClass3 = class(TClass1)
    constructor Create(Names: TStrings); reintroduce; overload; 
    constructor Create(Name: string); reintroduce; overload; 
  end;

{ virtual constructors }

  TClass1Virtual = class(TObject)
    constructor Create; virtual;
  end;

  TClass2Virtual = class(TClass1Virtual)
    constructor Create; override;
  end;

  TClass3Virtual = class(TClass1Virtual)
    constructor Create(Names: TStrings); virtual; reintroduce; overload; 
    constructor Create(Name: string); virtual; reintroduce; overload; 
  end;

  TClass4Virtual = class(TClass4Virtual)
    constructor Create(Names: TStrings); override; 
  end;
Los daarvan kun je de constructor van TObject overriden door in een descendant class gewoon Create te declareren, eventueel met parameters naar keuze. Zie hierboven de constructor van TClass1, waar geen override directive aan is toegevoegd. Dat gaat goed, omdat de constructor Create van TObject een speciaal geval is - hij is niet expliciet gedeclareerd, maar er wordt wat compiler magic gebruikt. Zou je een willekeurige andere static method overriden, dan vindt de compiler dat niet lief en krijg je een warning.

Nog een kleine tip: geef een TStrings object in plaats van een TStringList mee. Dan werkt je code ook nog met andere descendants van TStrings dan TStringList. De daadwerkelijk via de parameter doorgegeven instantie is natuurlijk nooit een TStrings, want dat is een abstracte class.

Een goede grap mag vrienden kosten.


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
tomatoman, je stuurt me idd verder het bos in :)

Je verklaring met static en virtual constructors is wel correct op zich, maar het lost m'n probleem niet op. Als ik een constructor met nieuwe parameters als reintroduce en overload declareer, blijft volgende code insight de orginele constructor bestaan. Ook al reintroduce ik em zonder parameters als private...

LordLarry komt het dichtst in de buurt, vrees ik :'(

Maar dan vraag ik me nog steeds af: bijv TCustomForm.Create heeft de default constructor van z'n ancestor TObject wel verborgen. Hoe hebben ze dat dan? Check code insight maar, geen *no parameters expected* als je TCustomForm.Create( intiept...

日本!🎌


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 20-05 14:02

Tomatoman

Fulltime prutser

Waarom handel je de default constructor niet gewoon af?
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
type
  TMyClass = class
    constructor Create; overload;
    constructor Create(Names: TStringList); overload;
    constructor Create(const Name: string); overload;
  end;

constructor TMyClass.Create;
begin
  Create('');  // roept eenvoudigweg Create(const Name: string) aan
  { Je zou ook Create(nil) kunnen gebruiken }
end;


[Edit]
In regel 20 en 25 van de code van LordLarry staat 'inherited Create;'. Normaliter is dat een goed idee, maar aangezien de class een directe descendant van TObject is, kun je die regels net zo goed weglaten. TObject implementeert Create namelijk niet daadwerkelijk, het is een soort placeholder voor een - alleen in TObject! - abstracte constructor. Daarom is reintroduce of override ook niet nodig om de TObject.Create te overriden.

[ Voor 39% gewijzigd door Tomatoman op 12-10-2004 21:30 ]

Een goede grap mag vrienden kosten.


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
Maar dat wil ik niet :)

Ik heb al wat beters gevonden:
Delphi:
1
2
3
4
5
6
7
8
type
  TMyBaseClass = class
    constructor Create(const Name: string); reintroduce;
  end;

  TMyClass = class(TMyBaseClass)
    constructor Create(Names: TStrings); overload;
  end;

Dat doet de trick. Het werkt niet zoals je zou verwachten, maar het werkt afdoende zo.

Trouwens, je verhaal over TObject: ik doe inherited altijd wel. Gewenning enzo. Als ik het niet zou doen, zou ik het misschien vergeten op een plek waar het wel moet. En het kan geen kwaad en het staat netjes, dus :)

[ Voor 25% gewijzigd door _Thanatos_ op 12-10-2004 21:40 ]

日本!🎌


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

_Thanatos_ schreef op 12 oktober 2004 @ 20:45:
Maar dan vraag ik me nog steeds af: bijv TCustomForm.Create heeft de default constructor van z'n ancestor TObject wel verborgen. Hoe hebben ze dat dan? Check code insight maar, geen *no parameters expected* als je TCustomForm.Create( intiept...
TCustomForm heeft helemaal geen geoverloade constructoren. Zoals ik al zei krijg je jouw situatie alleen als je overload. Anders wordt de default constructor gewoon gehide zoals Curry684 al voorspelde.

We adore chaos because we like to restore order - M.C. Escher


  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 22:17

Delphi32

Heading for the gates of Eden

Ik sluit me even aan bij LL, maar dan met een code sample:
code:
1
2
3
4
  TSomeObject = class(TObject)
  public
    constructor Create(const aName : string);
  end;


Als ik ergens een object wil maken van TSomeObject dan gaat dat alleen als volgt:
code:
1
2
3
4
5
6
procedure TForm1.Button1Click(Sender: TObject);
var
  myObject : TSomeObject;
begin
  myObject := TSomeObject.Create('MyName');
end;


Als ik de parameter aName weglaat bij de call naar Create dan krijg ik een compile error. Terecht dus, want door mijn nieuwe constructor is de oude verborgen.
Overload of reintroduce zijn hier dus gewoon niet op z'n plaats.
Disclaimer: getest in D5, meer kan ik je niet bieden atm :)
Pagina: 1