Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if a class implements an interface, with respecting supersets?

I am learning about COM and Interfaces and have following experimental code:

type
  IA = interface(IInterface)
  ['{C9C5C992-3F67-48C5-B215-7DCE6A61F0E8}']
  end;

  IB = interface(IA)
  ['{F1799437-AD12-471B-8716-F1D93D1692FC}']
  end;

  IC = interface(IB)
  ['{01780E8C-C47D-468E-8E42-4BFF3F495D51}']
  end;

  TBO = class(TInterfacedObject, IB)
  end;

procedure TForm1.FormCreate(Sender: TObject);
var
  x: TBO;
  a: IInterface;
begin
  x := TBO.Create;
  IInterface(x)._AddRef;

  if Assigned(TBO.GetInterfaceEntry(IA)) then memo1.lines.add('GetInterfaceEntry IA: OK'); // Why not?
  if Assigned(TBO.GetInterfaceEntry(IB)) then memo1.lines.add('GetInterfaceEntry IB: OK');
  if Assigned(TBO.GetInterfaceEntry(IC)) then memo1.lines.add('GetInterfaceEntry IC: OK');

  if x.QueryInterface(IA, a)=S_OK then memo1.lines.add('QueryInterface TA: OK'); // Why not?
  if x.QueryInterface(IB, a)=S_OK then memo1.lines.add('QueryInterface TB: OK');
  if x.QueryInterface(IC, a)=S_OK then memo1.lines.add('QueryInterface TC: OK');

  if Supports(TBO, IA) then memo1.lines.add('Supports TA: OK'); // Why not?
  if Supports(TBO, IB) then memo1.lines.add('Supports TB: OK');
  if Supports(TBO, IC) then memo1.lines.add('Supports TC: OK');

  if Supports(x, IA, a) then memo1.lines.add('Supports(2) TA: OK'); // Why not?
  if Supports(x, IB, a) then memo1.lines.add('Supports(2) TB: OK');
  if Supports(x, IC, a) then memo1.lines.add('Supports(2) TC: OK');
end;

Output:

GetInterfaceEntry IB: OK
QueryInterface TB: OK
Supports TB: OK
Supports(2) TB: OK

But I need:

GetInterfaceEntry IA: OK
GetInterfaceEntry IB: OK
QueryInterface TA: OK
QueryInterface TB: OK
Supports TA: OK
Supports TB: OK
Supports(2) TA: OK
Supports(2) TB: OK

I understand that IB is a superset of IA due to the Interface inheritance. In my understanding, since TBO implements IB, it automatically implements IA. But why does Supports(), QueryInterface(), GetInterfaceEntry() return false?

How do I query if TBO implements IA directly OR indirectly, i.e. by implementing a superset of IA? I need both, a static class function like GetInterfaceEntry and a dynamic object reference variant like QueryInterface.

like image 913
Daniel Marschall Avatar asked Jul 11 '14 19:07

Daniel Marschall


People also ask

How do you know if a class implements an interface?

To declare a class that implements an interface, you include an implements clause in the class declaration. Your class can implement more than one interface, so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class.

How do you check if an object is of a specific interface?

isInterface() method The isArray() method of the Class class is used to check whether a class is an interface or not. This method returns true if the given class is an interface. Otherwise, the method returns false , indicating that the given class is not an interface.

Which keyword validates whether a class implements an interface?

With the aim to make the code robust, i would like to check that the class implements the interface before instantiation / casting. I would like the the keyword 'instanceof' to verify a class implements an interface, as i understand it, it only verifies class type.

Is it OK if a class definition implements two interfaces?

8. Is it OK if a class definition implements two interfaces, each of which has the same definition for the constant PI? a. No---if a class implements several interfaces, each constant must be defined in only one interface.


1 Answers

This is a known quirk of Delphi. Even though IB inherits from IA, TBO must explicitly specify both IA and IB in order for Supports() to retrieve both interfaces.

TBO = class(TInterfacedObject, IA, IB)

I forget the technical reason for this. Something to do with a limitation in how the compiler generates the interface table for TBO. It does not automatically include inherited interfaces.

like image 179
Remy Lebeau Avatar answered Nov 15 '22 04:11

Remy Lebeau