Simple answer is no. Your class *DOES NOT* support IFirstDescendant. You must explicitly tell the compiler that your class supports IFirstDescendant:
TNewClass = class(TInterfacedObject,IFirstDescendant,ISecondDescendant) Interface inheritance is *DIFFERENT* from class inheritance. The idea of interfaces is each interface is a complete and is independent of implementation, whereas a class declaration can be incomplete (eg. abstract base classes). When you implement an interface, you must implement it completely (you can still make any non-implemented methods abstract). Your example is a good one: Though ISecondDescendant inherits from IFirstDescendant, it is a different interface from IFirstDescendant and the only thing get from the inheritance is the short form of not having to redeclare IFirstDescendant methods in ISecondDescendant. So why doesn't Delphi treat TNewClass = class(TInterfacedObject,ISecondDescendant) as TNewClass = class(TInterfacedObject,IFirstDescendant,ISecondDescendant)? The answer is because a class may implement its interfaces independently and differently - eg. IFirstDescendent = interface (IInterface) procedure A; end; ISecondDescendent = interface (IFirstDescendent) procedure X; end; TNewClass = class(TInterfacedObject,IFirstDescendant,ISecondDescendant) procedure A; procedure B; procedure X; procedure IFirstDescendant.A = A; procedure ISecondDescendant.A = B; end; TNewClass implements IFirstDescendent using procedure A, and ISecondDescendant using procedures B and X. ie. p := TNewClass.Create; a := p; b := p; a.A performs a different operation than b.A. and even if you; a := b; a.A -> actually calls TNewClass.B! At compile time: TInterfacedObject implements IInterface TNewClass implements *ONLY* ISecondDescendant (its base class, TInterfacedObject, implements IInterface). Internally, Delphi creates a separate v-table for each interface a class implements, but only one v-table for the class members. So: TObject ==> has one v-table TInterfacedObject = class (TObject, IInterface) ==> has two v-tables: 1. v-table for TInterfacedObject, which is made up of the v-table for TObject, plus any new or overriden method members of TInteracedObject. 2. v-table for IInterface TNewClass = class (TInterfacedObject,ISecondDescendant) ==> has 3 v-tables: 1. v-table for TNewClass, which is made up of the v-table for TObject, plus any new or overriden method members of TInteracedObject., plus new or overriden method members of TNewClass. 2. v-table for IInterface 3. v-table for ISecondDescendant There is no v-table created for IFirstDescendant. However, the v-table for ISecondDescendant is made up of the v-table for IInterface, plus all new methods from IFirstDescendant, plus all new methods from ISecondDescendant. Then at run time: Each instance of the object you create will contain: 1. A reference to the object's v-table 2. The object's data members 3. One reference to the v-table for each directly supported interface. Using your example, an instance of TNewClass that is stored at location p will look like: p -> reference to TNewClass's v-table p+4 .. p+n+3 -> TInterfacedObject data members (n - total number of bytes) p+n+4 -> reference to IInterface p+n+8 .. p+n+m+7 -> data members added by TNewClass (m - total number of bytes) p+n+m+8 -> reference to ISecondDescendant TNewClass.Create returns p Casting p as IInterface returns p+n+4 Casting p as ISecondDescendant returns p+n+m+8 Optimation: The compiler will optimise v-tables for interface declarations at compile time so that linear sequences of inheritance without method overrides use the same v-table. Using your example, both IFirstDescendant and ISecondDescendant will point to the same v-table. If you declared TNewClass as: TNewClass = class(TInterfacedObject, IFirstDescendent,ISecondDescendant) then your instance will look like p -> reference to TNewClass's v-table p+4 .. p+n+3 -> TInterfacedObject data members (n - total number of bytes) p+n+4 -> reference to IInterface p+n+8 .. p+n+m+7 -> data members added by TNewClass (m - total number of bytes) p+n+m+8 -> reference to ISecondDescendant (also used for IFirstDescendent) TNewClass.Create returns p Casting p as IInterface returns p+n+4 Casting p as IFirstDescendent returns p+n+m+8 Casting p as ISecondDescendant returns p+n+m+8 If however, your interface declarations are non-linear: IOtherDescendent = interface (IFirstDescendent) TNewClass = class(TInterfacedObject, IFirstDescendent,ISecondDescendant,IOtherDescendent) then the instance will look like: p -> reference to TNewClass's v-table p+4 .. p+n+3 -> TInterfacedObject data members (n - total number of bytes) p+n+4 -> reference to IInterface p+n+8 .. p+n+m+7 -> data members added by TNewClass (m - total number of bytes) p+n+m+8 -> reference to ISecondDescendant p+n+m+12 -> reference to IOtherDescendent TNewClass.Create returns p Casting p as IInterface returns p+n+4 Casting p as ISecondDescendant returns p+n+m+8 Casting p as IOtherDescendent returns p+n+m+12 Whether the compiler chooses to use ISecondDescendant or IOtherDescendent for IFirstDescendent cannot be predicted. Therefore casting p as IFirstDescendent can return either p+n+m+8 or p+n+m+12. Each interface implemented by a class has the potential to add one more reference to the instance data, bloating it by 4-bytes. This is why Delphi does not automatically treat TNewClass = class(TInterfacedObject,ISecondDescendant) as TNewClass = class(TInterfacedObject,IFirstDescendant,ISecondDescendant)? Doing so could bloat instances of TNewClass. Leave it up to the programmer which interfaces to implement and how much bloat to add to instances. Does this all make sense? Regards, Dennis. ----- Original Message ----- From: "Todd Martin" <[EMAIL PROTECTED]> To: "Multiple recipients of list delphi" <[EMAIL PROTECTED]> Sent: Friday, June 13, 2003 1:52 PM Subject: [DUG]: Interface Inheritance > Hi > > Does anyone know if there's a way to test for interface inheritance? > For example > > IFirstDescendant = interface(IInterface); > ISecondDescendant = interface(IFirstDescendant); > > TNewClass = class(TInterfacedObject,ISecondDescendant); > > NewObject = TNewClass.Create; > > is there a way to see whether NewObject supports the interface > "IFirstDescendant" > > NewObject.GetInterface(IFirstDescendant,Descendant) > returns a nil pointer for Descendant. > > I'm thinking the VTable entry for the ISecondDescendant interface, might > link back to IFirstDescendant somehow. > > Todd. > > > -------------------------------------------------------------------------- - > New Zealand Delphi Users group - Delphi List - [EMAIL PROTECTED] > Website: http://www.delphi.org.nz > To UnSub, send email to: [EMAIL PROTECTED] > with body of "unsubscribe delphi" > Web Archive at: http://www.mail-archive.com/delphi%40delphi.org.nz/ > --------------------------------------------------------------------------- New Zealand Delphi Users group - Delphi List - [EMAIL PROTECTED] Website: http://www.delphi.org.nz To UnSub, send email to: [EMAIL PROTECTED] with body of "unsubscribe delphi" Web Archive at: http://www.mail-archive.com/delphi%40delphi.org.nz/