On 28.09.2013 16:37, Xiangrong Fang wrote:
2013/9/28 Sven Barth <pascaldra...@googlemail.com
<mailto:pascaldra...@googlemail.com>>


    On second sight your solution is not correct, because you are using
    Clone inside your parent class which would not use the (non-virtual)
    Clone you created.


​What If I make Clone virtual? If by adding "virtual" to Clone, the
problem is solved, then what's the difference between virtual Clone and
the method you provided?

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.

​

    === code begin ===

    type
       generic TTree<T> = class
       private type
         TSelfType = TTree;
         TSelfClass = class of TSelfType; // earlier I suggested TTree
    which 2.6.2 does not support


​This compiles, however, if I remove my version of TIntTree (i.e.
implement a Clone in it and call parent's DoClone), then the main
program does not compile, it says:

demo2.lpr(20,13) Error: Incompatible types: got "TIntTree.TTree$LongInt"
expected "TIntTree"

I then can either:

1) add a Clone method to TIntTree and do a typecast inside it, as you said.
2) do a typecast in the main program, i.e. it2 := it1.Clone as TIntTree.

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. ;)


So, I guess the problem is solved?  I have two further questions:

1) Why class of TTree does not work in 2.6.2 but class of TSelfType
worked? Is it a problem of generics in 2.6.2, or it is *not* related to
generics?   I feel that TSelfType is same as TTree?

It's a problem of generics in 2.6.2. Principially TSelfType is the same as TTree, but the 2.6.2 compiler treats them a little bit differently.


2) What is the difference between the following:

- it2 := TIntTree(it1.Clone);
- it2 := it1.Clone as TIntTree;

The latter does a conversion at runtime, so if "it1.Clone" returns an instance that is not compatible with TIntTree (for example a TObject or a TTree<LongInt>) then an exception will be raised. The former does not raise such an exception (but will show you a warning if you try to e.g. convert a TTree<LongInt> to a TTree<String>, but AFAIK the "as" will show that warning as well) and does not require additional runtime code (thus if you know that a e.g. TTree<LongInt> variable really contains a TIntTree instance you can use the hard typecast). If you compile code with -CR or {$OBJECTCHECKS ON} then the hard typecast will be the same as "as".


Where in the official document can I find the behavior/definition of "as"?

Here: http://freepascal.org/docs-html/ref/refsu45.html#x135-14500012.8.7 (Chapter Expressions => Class operators)

Regards,
Sven
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply via email to