Toon posts:

[delphi] eigen class in eigen class (vervolg)

Pagina: 1
Acties:

Verwijderd

Topicstarter
Naar aanleiding van een ieder draadje "eigen class in eigen class" kom ik nu met een vervolg vraag.

Uitgaande van een eigen class TMyClassA. Deze class bevat twee andere door mijzelf gedefinieerde classes.
Te weten TMyClassB, TMyClassC.
code:
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
35
36
37
38
39
40
41
42
type
  TMyClassA = class(TObject)
    private
      FMyClassB: TMyClassB;
      FMyClassC: TMyClassC;

    public
      constructor Create; override;
      destructor Destroy; override;

      procedure SetMyClassB(const Value: TMyClassB);
      procedure SetMyClassC(const Value: TMyClassC);

      property MyClassB: TMyClassB read FMyClassB write SetMyClassB;
      property MyClassC: TMyClassC read FMyClassC write SetMyClassC;
end;

implementation

constructor TMyClassA.Create;
begin
  inherited Create;
    FMyClassB := TMyClassB.Create;
end;

destructor TMyClassA.Destroy;
begin
    FMyClassB.Free;
  inherited;
end;

procedure TMyClassA.SetMyClassB(const Value: TMyClassB);
begin
  if Assigned(Value) then
    FMyClassB.Assign(Value);
end;

procedure TMyClassA.SetMyClassC(const Value: TMyClassC);
begin
  if Assigned(Value) then
    FMyClassC.Assign(Value);
end;

OK, zoals jullie zien wordt MyClassB gelijk aangemaakt op de create van MyClassA. MyClassC wil ik echter op zelf gekozen momenten aanmaken en afsluiten.

Nou dacht ik dat op de volgende wijze te doen:
code:
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
35
36
37
38
39
40
41
unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MyClassA_Bestand;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  MyA: TMyClassA;

implementation



{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
      MyA := TMyClassA.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
      MyA.MyClassC : TMyClassC.Create;
      // voer hier een memberfunctie van MyClassC uit
end;

end.

Maar dit werkt niet...
[Error] main.pas(38): Undeclared identifier: <<Memberfunctie MyClassC>>
Is er iemand met enig idee wat hier misgaat en waarom?

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:57
Het instantieren van een object van Class C doe je volgens mij goed.
Hij kent de member functie niet, ben je wel zeker dat die member functie gedeclareerd is in uw class en heb je geen typefouten gemaakt?

https://fgheysels.github.io/


Verwijderd

Topicstarter
Ik ben er zeker van dat ik een bestaande memberfunctie aanroep. Dus daar kan m.i. het probleem niet zitten.

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:57
De unit waarin je die class C gedefinieerd hebt staat in uw uses list?
't Zal wel anders zou je al een andere fout krijgen.

https://fgheysels.github.io/


Verwijderd

De code die je nu geeft, compileert gewoon bij mij...

Maar ik kan je wel zeggen dat
code:
1
FMyClassC.Assign(Value);

in TMyClassA.SetMyClassC, fout gaat als FMyClassC = nil.

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:57
Op zaterdag 16 februari 2002 12:36 schreef DiFool het volgende:
De code die je nu geeft, compileert gewoon bij mij...
Hij krijgt een compile error als hij een bepaalde member functie oproept.
Kun je misschien eens de class C posten en de code posten waar je die member functie oproept.
Maar ik kan je wel zeggen dat
code:
1
FMyClassC.Assign(Value);

in TMyClassA.SetMyClassC, fout gaat als FMyClassC = nil.
Ja, da's normaal dat je dan een access violation krijgt. Je verwijst nl. naar een niet gealloceerd stuk geheugen.

https://fgheysels.github.io/


Verwijderd

Topicstarter
Ik heb hard zitten blokken en piekeren. Een hoop zitten veranderen en later weer terug zitten draaien, maar nu werkt het.

Feitelijk is er niets anders dan aan het begin van dit topic, maar het werkt.

Bedankt in ieder geval

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 22:24

Tomatoman

Fulltime prutser

In de definitie van TMyClassA zitten een paar eigenaardigheden.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type
  TMyClassA = class(TObject)
    private
      FMyClassB: TMyClassB;
      FMyClassC: TMyClassC;

    public
      constructor Create; override;
      destructor Destroy; override;

      procedure SetMyClassB(const Value: TMyClassB);
      procedure SetMyClassC(const Value: TMyClassC);

      property MyClassB: TMyClassB read FMyClassB write SetMyClassB;
      property MyClassC: TMyClassC read FMyClassC write SetMyClassC;
end;

Ten eerste override je de constructor, terwijl die in TObject nog niet is geïntroduceerd. Je moet 'override' dus vervangen door 'virtual', anders compileert je code niet eens.

Ten tweede heb je twee properties die public zijn. Die gebruik je als accessor voor het field FMyClassB (en FMyClassC). Daarvoor kunnen twee redenen zijn:
1) je wilt de details van de implementatie van FMyClassB verbergen;
2) je wilt gebruik maken van polymorfisme (simpel gezegd: je wilt in een descendant van TMyClassA het gedrag van de property veranderen).
Dat tweede punt sla ik even over, maar als je de details wilt verbergen (punt 1), moet je SetMyClassB private maken, want anders is de moeite voor niets geweest. Dus:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
type
  TMyClassA = class(TObject)
    private
    FMyClassB: TMyClassB;
    FMyClassC: TMyClassC;
    procedure SetMyClassB(const Value: TMyClassB);
    procedure SetMyClassC(const Value: TMyClassC);
    public
    constructor Create; virtual;
    destructor Destroy; override;
    property MyClassB: TMyClassB read FMyClassB write SetMyClassB;
    property MyClassC: TMyClassC read FMyClassC write SetMyClassC;
  end;

Ten derde bevat je code bugs! Je maakt twee objecten aan - FMyClassB en FMyClassC. In feite zijn dit zijn pointers naar de objecten en niet de objecten zelf. Stel dat je nu de code
MyClassA.MyClassB := nil;
uitvoert. Dan krijgt de pointer FMyClassB de waarde nil, maar het object bestaat nog steeds! Dat object wordt ook nergens meer vernietigd, zodat je een geheugenlek hebt. Waarschijnlijk wil je niet eens dat MyClassB naar een ander object kan verwijzen dan het object dat in de constructor wordt gecreëerd, maar wil je gewoon dat de gebruiker toegang heeft tot de properties en methods van dat object. Dat kun je eenvoudigweg doen door MyClassB read-only te maken:
code:
1
2
3
4
5
6
7
8
9
10
11
type
  TMyClassA = class(TObject)
    private
    FMyClassB: TMyClassB;
    FMyClassC: TMyClassC;
    public
    constructor Create; virtual;
    destructor Destroy; override;
    property MyClassB: TMyClassB read FMyClassB;
    property MyClassC: TMyClassC read FMyClassC;
  end;

Je kunt nu nog steeds code uitvoeren als
MyClassA.MyClassB.DoeDit;
MyClassA.MyClassB.Kleur := clRed;

Een goede grap mag vrienden kosten.

Pagina: 1