[fpc-pascal] class inheritance and type incompatibility
Sven Barth
pascaldragon at googlemail.com
Thu Sep 26 14:02:57 CEST 2013
On 26.09.2013 08:39, Xiangrong Fang wrote:
> Hi All,
>
> I have the following program:
>
> 1 program test;
> 2 {$mode objfpc}{$H+}
> 3 uses tree;
> 4 type
> 5 TIntTree = class(specialize TTree<Integer>)
> 6 public
> 7 function Clone: TIntTree;
> 8 end;
> 9 function TIntTree.Clone: TIntTree;
> 10 begin
> 11 Result := TIntTree(inherited Clone);
> 12 end;
> 13 var
> 14 it1, it2 : TIntTree;
> 15 begin
> 16 it1 := TIntTree.Create(1, nil);
> 17 it2 := it1.Clone;
> 18 WriteLn(it1.ClassName);
> 19 WriteLn(it2.ClassName);
> 20 end.
>
> Which output:
>
> TIntTree
> TIntTree.TTree$LongInt
>
> The source code of TTree is here:
> https://github.com/xrfang/fpcollection/blob/master/src/units/tree.pas
>
> Why the typecast on line 11 does not work? How to modify the code so
> that the cloned object has same type as the original one?
Please always think through this without generics.
Your code looks roughly like this:
=== code begin ===
type
TTreeInteger = class
function Clone: TTreeInteger;
end;
TTreeInt = class(TTreeInteger)
function Clone: TTreeInt;
end;
function TTreeInteger.Clone: TTreeInteger;
begin
Result := TTreeInteger.Create;
end;
function TTreeInt.Clone: TTreeInt;
begin
Result := TTreeInt(inherited Clone);
end;
=== code end ===
As you can see you are constructing a TTreeInteger class inside
TTreeInteger.Clone and nothing in the world afterwards can turn it into
a TTreeInt. If you'd use the "as" operator in TTreeInt.Clone then you'd
even get an exception, because you can not assign a TTreeInteger
instance(!) to a TTreeInt.
What should work is the following (now with generics again):
=== code begin ===
type
TTree<T> = class
private type
TSelfClass = class of TTree;
public
function Clone: TTree;
end;
function TTree.Clone: TTree;
begin
Result := TSelfClass(Self.ClassType).Create(Data, FParent);
(* ... *)
end;
=== code end ===
Note: The cast to TSelfClass is necessary to have access to the
overloaded constructor you added for TTree<>.
Regards,
Sven
More information about the fpc-pascal
mailing list