On 29.09.2013 04:47, Xiangrong Fang wrote:
2013/9/29 Sven Barth <pascaldra...@googlemail.com
<mailto:pascaldra...@googlemail.com>>
If you want to override the virtual Clone method of TTree<LongInt>
in TIntTree you need to use the same result type + override or
otherwise you gain nothing, because the compiler will not consider
the method as overloaded and use the Clone method of TTree<LongInt>
inside TTree<LongInt>'s methods instead.
Yes, you are right, for virtual method, you need have exactly same
type... But this leads me to think how the generics are implemented?
The important things about generics:
- The generic type itself (in this case TTree<>) does *not* exist inside
the code (bugs not withstanding...), only the textual representation of
the generic exists as metadata inside the PPU (which you can not access
from a program)
- When specializing a generic the compiler loads this metadata and
reparses the textual representation whereby the generic type parameters
are replaced by the types you specified, so in code a "specialize
TTree<Integer>" looks like a "TTree<T>" which you manually have made
non-generic and replaced each occurence of "T" with "Integer".
For
example:
=== snippet 1 ===
type
TIntTree = class(specialize TTree<Integer>)
public
function Clone: TTree; override;
end;
=== end of snippet 1 ===
This will leads to a compile error: Generics without specialization
cannot be used as a type for a variable.
"TTree" is not valid anywhere except inside the declaration of the
generic (and only in non-Delphi modes).
If so, why in the code TTree can be used everywhere, for example:
=== snippet 2 ===
function TTree.Level: Cardinal;
var
n: TTree; <-- here TTree is not specialized.
begin
... ...
end;
=== end of snippet 2 ===
In snippet 1, why the compiler don't treat the TTree same as its own
type i.e. TIntTree? I imagine that TTree in snippet 1 is logically
similar to TObject. I mean, a class's method is of course possible to
return a value of its parent's type or any other class's instance?
In case of generics in non-Delphi modes the own class name without
generic parameters (here "TTree") is a place holder for the own type of
the generic. The compiler replaces any reference to this type with
references to the generic you are declaring. If you now specialize a
generic (e.g. "specialize TTree<LongInt>") all those references are now
handled as references to "TTree<LongInt>".
Would you please show how exactly you changed the code? With all
those methods calling each other it's a bit hard to imagine in my
head what you changed. ;)
With your TSelfClass solution in TTree, I mean either:
=== solution 1 ===
type
TIntTree = class(specialize TTree<Integer>
public
function Clone: TIntTree;
end;
function TIntTree.Clone: TIntTree;
begin
Result := TIntTree(inherited Clone); //typecast in TIntTree
end;
=== end of solution 1===
or:
=== solution 2 ===
type
TIntTree = class(specialize TTree<Integer>)
end;
begin //main
it2 := TIntTree(it1.Clone); //typecast in main program
end.
=== end of solution 2 ===
Are both solutions correct?
Yes, correct are both.
Regards,
Sven
_______________________________________________
fpc-pascal maillist - fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal