Results 1 to 8 of 8

Thread: Assign en inheritance.

  1. #1
    Delphi & OO in Vlaanderen SamWitse's Avatar
    Join Date
    Sep 2007
    Location
    Brussel
    Posts
    833

    Question Assign en inheritance.

    Beste Delphinauten,

    Een very basic inheritance probleem, waar ik even geen uitweg in zie.

    3 klassieke klassen TFiguur, TCirkel = class(TFiguur), TVierkant = class(TFiguur).
    2 klassen TMaster en TSlave= class(TMaster).
    TMaster bevat een TFiguur.

    Delphi Code:
    1. type<br>TFiguur = class<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; private<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { private declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FKleur: string;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { public declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; procedure Assign ( AFiguur:TFiguur ) ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; property Kleur: string read FKleur write FKleur ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>TCirkel = class (TFiguur)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; private<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { private declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FStraal: integer;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { public declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; procedure Assign ( ACirkel:TCirkel );<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; property Straal: integer read FStraal write FStraal ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>TVierkant = class (TFiguur)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; private<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { private declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FZijde: string;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { public declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; procedure Assign ( AVierkant: TVierkant ) ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; property Zijde: string read FZijde write FZijde ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>TMaster = class<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; private<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { private declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FFiguur: TFiguur ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FWaarde: integer ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { public declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; constructor Create;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; procedure Assign ( AMaster: TMaster ) ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; property Figuur: TFiguur read FFiguur write FFiguur ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; property Waarde: integer read FWaarde write FWaarde ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>TSlave = class(TMaster)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;private<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ private declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;FLeeftijd: integer ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ public declarations }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; constructor Create;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; procedure Assign ( ASlave: TSlave ) ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; property Leeftijd:integer read FLeeftijd write FLeeftijd ;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br><br><br><br>implementation<br><br>{ TFiguur }<br><br>procedure TFiguur.Assign(AFiguur: TFiguur);<br>begin<br>&nbsp; FKleur := AFiguur.Kleur<br>end;<br><br>{ TCirkel }<br><br>procedure TCirkel.Assign(ACirkel: TCirkel);<br>begin<br>&nbsp; inherited Assign (TFiguur(ACirkel)) ; {Om de Kleur op te vullen}<br>&nbsp; FStraal := ACirkel.FStraal<br>end;<br><br>{ TVierkant }<br><br>procedure TVierkant.Assign(AVierkant: TVierkant);<br>begin<br>&nbsp; inherited Assign (TFiguur(AVierkant)) ; {Om de Kleur op te vullen}<br>&nbsp; FZijde := AVierkant.FZijde<br>end;<br><br>{ TMaster }<br><br>procedure TMaster.Assign(AMaster: TMaster);<br>begin<br>&nbsp; FFiguur.Assign(AMaster.FFiguur);<br>&nbsp; FWaarde := AMaster.FWaarde<br>end;<br><br>constructor TMaster.Create;<br>begin<br>&nbsp; inherited;<br>&nbsp; FFiguur := TFiguur.Create<br>end;<br><br>{ TSlave }<br><br>procedure TSlave.Assign(ASlave: TSlave);<br>begin<br>&nbsp; inherited Assign (TMaster(ASlave)) ;{Om Figuur en waarde te copiëren}<br>&nbsp; FLeeftijd := ASlave.FLeeftijd<br>end;<br><br>constructor TSlave.Create;<br>begin<br>&nbsp; inherited;<br>{Geen bijkomende objecten te creëren}<br>end;

    De methods Assign zorgen voor een deep copy van de objecten.

    Als ik nu een Slave maak met een TCirkel erin, en ik assign die aan een andere Slave, dan wordt de Cirkel niet mee gecopieerd!
    <br>
    Delphi Code:
    1. <br>var<br>&nbsp; MijnSlave: TSlave;<br>&nbsp; MijnCirkel: TCirkel ;<br>&nbsp; JouwSlave: TSlave ;<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>begin &nbsp; &nbsp; &nbsp;{Creatie van een Slave met een Cirkel als figuur}<br>&nbsp; MijnSlave:= TSlave.Create;<br>&nbsp; MijnCirkel := TCirkel.Create ;<br>&nbsp; MijnCirkel.Kleur := 'Geel' ;<br>&nbsp; MijnCirkel.Straal := 7 ;<br>&nbsp; MijnSlave.Waarde := 10 ;<br>&nbsp; MijnSlave.Leeftijd := 3 ;<br>&nbsp; MijnSlave.Figuur := MijnCirkel<br>end;<br><br>procedure TForm1.Button2Click(Sender: TObject);<br>begin<br>&nbsp; JouwSlave:= TSlave.Create ;<br>&nbsp; JouwSlave.Assign(MijnSlave); {Copiëren van MijnSlave naar JouwSlave}<br>end;<br><br>procedure TForm1.Button3Click(Sender: TObject);<br>var<br>&nbsp; DezeStraal: integer ;<br>begin<br>&nbsp; DezeStraal := TCirkel(JouwSlave.Figuur).Straal ;<br>&nbsp; Edit1.Text := IntToStr(DezeStraal)<br>end;

    Het resultaat (na het klikken op button1, button2 en button3) is 0, terwijl MijnCirkel wel degelijk straal 7 heeft.
    Waar gaat het mis?

    In procedure TMaster.Assign(AMaster: TMaster);

    wordt de figuur gecopiëerd dmv
    FFiguur.Assign(AMaster.FFiguur);

    maar die voert de Assign uit van TFiguur, en NIET de Assign van TCirkel.

    Hoe kan ik er voor zorgen dat in TMaster.Assign steeds de Assign van de juiste subclasse (TCirkel, TVierkant) wordt uitgevoerd, en niet deze van TFiguur?

    Sam.
    Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration.

    Sam Witse.
    Delphi & OO in Vlaanderen

  2. #2
    Delphi & OO in Vlaanderen SamWitse's Avatar
    Join Date
    Sep 2007
    Location
    Brussel
    Posts
    833
    Hopelijk is deze versie leesbaarder!

    Beste Delphinauten,

    Een very basic inheritance probleem, waar ik even geen uitweg in zie.

    3 klassieke klassen TFiguur, TCirkel = class(TFiguur), TVierkant = class(TFiguur).
    2 klassen TMaster en TSlave= class(TMaster).
    TMaster bevat een TFiguur.

    Delphi Code:
    1. type
    2. TFiguur = class
    3.           private
    4.             { private declarations }
    5.             FKleur: string;
    6.           public
    7.             { public declarations }
    8.             procedure Assign ( AFiguur:TFiguur ) ;
    9.             property Kleur: string read FKleur write FKleur ;
    10.           end;
    11.  
    12. TCirkel = class (TFiguur)
    13.           private
    14.             { private declarations }
    15.             FStraal: integer;
    16.           public
    17.             { public declarations }
    18.             procedure Assign ( ACirkel:TCirkel );
    19.             property Straal: integer read FStraal write FStraal ;
    20.           end;
    21.  
    22. TVierkant = class (TFiguur)
    23.           private
    24.             { private declarations }
    25.             FZijde: string;
    26.           public
    27.             { public declarations }
    28.             procedure Assign ( AVierkant: TVierkant ) ;
    29.             property Zijde: string read FZijde write FZijde ;
    30.           end;
    31.  
    32. TMaster = class
    33.           private
    34.             { private declarations }
    35.             FFiguur: TFiguur ;
    36.             FWaarde: integer ;
    37.           public
    38.             { public declarations }
    39.             constructor Create;
    40.             procedure Assign ( AMaster: TMaster ) ;
    41.             property Figuur: TFiguur read FFiguur write FFiguur ;
    42.             property Waarde: integer read FWaarde write FWaarde ;
    43.           end;
    44.  
    45. TSlave = class(TMaster)
    46.          private
    47.            { private declarations }
    48.            FLeeftijd: integer ;
    49.          public
    50.            { public declarations }
    51.             constructor Create;
    52.             procedure Assign ( ASlave: TSlave ) ;
    53.             property Leeftijd:integer read FLeeftijd write FLeeftijd ;
    54.           end;
    55.  
    56.  
    57.  
    58. implementation
    59.  
    60. { TFiguur }
    61.  
    62. procedure TFiguur.Assign(AFiguur: TFiguur);
    63. begin
    64.   FKleur := AFiguur.Kleur
    65. end;
    66.  
    67. { TCirkel }
    68.  
    69. procedure TCirkel.Assign(ACirkel: TCirkel);
    70. begin
    71.   inherited Assign (TFiguur(ACirkel)) ; {Om de Kleur op te vullen}
    72.   FStraal := ACirkel.FStraal
    73. end;
    74.  
    75. { TVierkant }
    76.  
    77. procedure TVierkant.Assign(AVierkant: TVierkant);
    78. begin
    79.   inherited Assign (TFiguur(AVierkant)) ; {Om de Kleur op te vullen}
    80.   FZijde := AVierkant.FZijde
    81. end;
    82.  
    83. { TMaster }
    84.  
    85. procedure TMaster.Assign(AMaster: TMaster);
    86. begin
    87.   FFiguur.Assign(AMaster.FFiguur);
    88.   FWaarde := AMaster.FWaarde
    89. end;
    90.  
    91. constructor TMaster.Create;
    92. begin
    93.   inherited;
    94.   FFiguur := TFiguur.Create
    95. end;
    96.  
    97. { TSlave }
    98.  
    99. procedure TSlave.Assign(ASlave: TSlave);
    100. begin
    101.   inherited Assign (TMaster(ASlave)) ;{Om Figuur en waarde te copiëren}
    102.   FLeeftijd := ASlave.FLeeftijd
    103. end;
    104.  
    105. constructor TSlave.Create;
    106. begin
    107.   inherited;
    108. {Geen bijkomende objecten te creëren}
    109. end;

    De methods Assign zorgen voor een deep copy van de objecten.

    Als ik nu een Slave maak met een TCirkel erin, en ik assign die aan een andere Slave, dan wordt de Cirkel niet mee gecopieerd!
    Delphi Code:
    1. var
    2.   MijnSlave: TSlave;
    3.   MijnCirkel: TCirkel ;
    4.   JouwSlave: TSlave ;
    5.  
    6. procedure TForm1.Button1Click(Sender: TObject);
    7. begin      {Creatie van een Slave met een Cirkel als figuur}
    8.   MijnSlave:= TSlave.Create;
    9.   MijnCirkel := TCirkel.Create ;
    10.   MijnCirkel.Kleur := 'Geel' ;
    11.   MijnCirkel.Straal := 7 ;
    12.   MijnSlave.Waarde := 10 ;
    13.   MijnSlave.Leeftijd := 3 ;
    14.   MijnSlave.Figuur := MijnCirkel
    15. end;
    16.  
    17. procedure TForm1.Button2Click(Sender: TObject);
    18. begin
    19.   JouwSlave:= TSlave.Create ;
    20.   JouwSlave.Assign(MijnSlave); {Copiëren van MijnSlave naar JouwSlave}
    21. end;
    22.  
    23. procedure TForm1.Button3Click(Sender: TObject);
    24. var
    25.   DezeStraal: integer ;
    26. begin
    27.   DezeStraal := TCirkel(JouwSlave.Figuur).Straal ;
    28.   Edit1.Text := IntToStr(DezeStraal)
    29. end;

    Het resultaat (na het klikken op button1, button2 en button3) is 0, terwijl MijnCirkel wel degelijk straal 7 heeft.
    Waar gaat het mis?

    In procedure TMaster.Assign(AMaster: TMaster);

    wordt de figuur gecopiëerd dmv
    FFiguur.Assign(AMaster.FFiguur);

    maar die voert de Assign uit van TFiguur, en NIET de Assign van TCirkel.

    Hoe kan ik er voor zorgen dat in TMaster.Assign steeds de Assign van de juiste subclasse (TCirkel, TVierkant) wordt uitgevoerd, en niet deze van TFiguur?

    Sam.
    Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration.

    Sam Witse.
    Delphi & OO in Vlaanderen

  3. #3
    Quote Originally Posted by SamWitse View Post
    De methods Assign zorgen voor een deep copy van de objecten.
    Waar gaat het mis?
    In procedure TMaster.Assign(AMaster: TMaster);
    wordt de figuur gecopiëerd dmv
    FFiguur.Assign(AMaster.FFiguur);
    maar die voert de Assign uit van TFiguur, en NIET de Assign van TCirkel.
    Eigenlijk geef je het zelf al aan. Als je Assign(FFiguur) doet dan worden alleen de properties van FFiguur gekopieerd (naar een bestaand object). En dat is dus alleen de kleur Geel (die wel netjes mee gaat). Straal wordt dan dus niet gekopieerd. (over het bestaande object kom ik hieronder terug) Je kunt wel een pointer naar je figuur-object meegeven maar dat is denk ik niet wat je wilt:

    Delphi Code:
    1. procedure TMaster.Assign(AMaster: TMaster);
    2. begin
    3.   FFiguur := AMaster.FFiguur;
    4.   // FFiguur.Assign(AMaster.FFiguur);
    5.   FWaarde := AMaster.FWaarde
    6. end;

    Let op: Je kopieert dan niet alles van AMaster.FFiguur maar je geeft de ALLEEN de pointer door aan TMaster.

    Jouw probleem is dat je een object binnen een object hebt. Die kun je niet zonder meer met alleen assigns kopiëren. Ik zie bijvoorbeeld wel dat je JouwSlave:= TSlave.Create; doet maar nergens maar je ook een KOPIE van je TFiguur aan (alleen een assign doet dat n.l. niet). Ik hoop dat ik het een beetje duidelijk uitleg.

    Als je echt een kopie van je TFiguur wilt hebben binnen je nieuwe JouwSlave-object dan zul je de TFiguur ook moeten "clonen".
    Zie: https://stackoverflow.com/questions/...-delphi-object

    In jouw geval kun je dan zoiets doen (er zullen misschien ook andere methodes zijn maar daar ben ik niet ingedoken):

    Delphi Code:
    1. type
    2.   TFiguur = class
    3.   private
    4.     { private declarations }
    5.     FKleur: string;
    6.   public
    7.     { public declarations }
    8.     procedure Assign(AFiguur: TFiguur);
    9.     property Kleur: string read FKleur write FKleur;
    10.     function Clone: TFiguur; virtual;
    11.   end;
    12.  
    13.   TCirkel = class(TFiguur)
    14.   private
    15.     { private declarations }
    16.     FStraal: Integer;
    17.   public
    18.     { public declarations }
    19.     procedure Assign(ACirkel: TCirkel);
    20.     property Straal: Integer read FStraal write FStraal;
    21.     function Clone: TFiguur; override;
    22.   end;
    23.  
    24.   TVierkant = class(TFiguur)
    25.   private
    26.     { private declarations }
    27.     FZijde: string;
    28.   public
    29.     { public declarations }
    30.     procedure Assign(AVierkant: TVierkant);
    31.     property Zijde: string read FZijde write FZijde;
    32.     function Clone: TFiguur; override;
    33.   end;
    34.  
    35. implementation
    36.  
    37. procedure TFiguur.Assign(AFiguur: TFiguur);
    38. begin
    39.   FKleur := AFiguur.Kleur
    40. end;
    41.  
    42. function TFiguur.Clone: TFiguur;
    43. begin
    44.   Result := TFiguur.Create;
    45.   TFiguur(Result).Assign(Self);
    46. end;
    47.  
    48. { TCirkel }
    49.  
    50. procedure TCirkel.Assign(ACirkel: TCirkel);
    51. begin
    52.   inherited Assign(TFiguur(ACirkel)); { Om de Kleur op te vullen }
    53.   FStraal := ACirkel.FStraal;
    54. end;
    55.  
    56. function TCirkel.Clone: TFiguur;
    57. begin
    58.   Result := TCirkel.Create;
    59.   TCirkel(Result).Assign(Self);
    60. end;
    61.  
    62. { TVierkant }
    63.  
    64. procedure TVierkant.Assign(AVierkant: TVierkant);
    65. begin
    66.   inherited Assign(TFiguur(AVierkant)); { Om de Kleur op te vullen }
    67.   FZijde := AVierkant.FZijde
    68. end;
    69.  
    70. function TVierkant.Clone: TFiguur;
    71. begin
    72.   Result := TVierkant.Create;
    73.   TVierkant(Result).Assign(Self);
    74. end;

    Dan heb je voor alles een .Clone functie (die inherited en overridden is zodat ook het juiste object gekopieerd wordt).

    In TMaster doe je dan dit:
    Delphi Code:
    1. procedure TMaster.Assign(AMaster: TMaster);
    2. begin
    3.   FFiguur := AMaster.FFiguur.Clone;
    4.   FWaarde := AMaster.FWaarde
    5. end;

    En dan zou het moeten werkten. De AMaster.FFiguur.Clone roept de uiteindelijke inherited "juiste" .Clone aan zodat de correcte figuur aangemaakt wordt en toegekend wordt.

  4. #4
    Delphi & OO in Vlaanderen SamWitse's Avatar
    Join Date
    Sep 2007
    Location
    Brussel
    Posts
    833
    Dank je Rik,

    Een heel juiste en duidelijke uitleg. Ik zat 'vast' met enkel Assign of enkel Clone. De combinatie van beide is volkomen logisch en een juiste oplossing!

    Nog een bemerking:

    Bij
    Delphi Code:
    1. function TVierkant.Clone: TFiguur;
    2. begin
    3.   result := TVierkant.Create ;
    zou je verwachten dat Delphi weet dat result een TVierkant is, en verlogens

    Delphi Code:
    1. Result.Assign(Self)

    de assign van een TVierkant zou uitvoeren. Helaas, je moet result nog typecasten.



    Sam.
    Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration.

    Sam Witse.
    Delphi & OO in Vlaanderen

  5. #5
    Quote Originally Posted by SamWitse View Post
    Helaas, je moet result nog typecasten.
    Ja, omdat je result van elke .Clone functie moet definiëren als TFiguur moet je die wel typecasten om de goede Assign te pakken.

    Reden waarom je de result van Clone moet definiëren als TFiguur is omdat je override wilt gebruiken in de inherited classes. Je wilt dus TFiguur.Clone kunnen doen en als de TFiguur een TCirkel bevat wil je dat de TCirkel.Clone uitgevoerd wordt. En override kun je alleen gebruiken als de parameters hetzelfde blijven. Dus Result van .Clone moet altijd TFiguur zijn (het kan echter wel een TCirkel "bevatten").

  6. #6
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Of assign ook vererven (zoals in Delphi tcomponent)

  7. #7
    Overigens...
    Je zou het volgens mij nog generieker op kunnen lossen.
    Lees het volgende hoofdstuk maar eens:
    http://castle-engine.io/modern_pasca...ass_references

    Dat betekend dat je met één .Clone functie in de parent-class uit zou kunnen.
    Dat combinerend met een Assign die ook virtual is en overriden kun je dus alles in één .Clone doen.

    Je zult dan wel ook Assign moeten overriden in je inherited classes.
    http://castle-engine.io/modern_pasca...sistent_assign

    (Ah, Macro is me nét voor)

  8. #8
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Zie ook https://stackoverflow.com/questions/...041906#4041906

    ongeveer hetzelfde idee, maar dan met een default parameter om "gewoon" te dupliceren.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •