program intf_no_class; ///// was tmanintf;
{$mode objfpc}
{$WARN 5028 off : Local $1 "$2" is not used}
type
TInterface = class
public
function QueryInterface(constref {%H-}IID: TGUID;{%H-} out {%H-}Obj): HResult; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
function _AddRef: LongInt; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual; abstract;
function _Release: LongInt; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual; abstract;
end;
TRawInterface = class(TInterface)
public
function _AddRef: LongInt; override;
function _Release: LongInt; override;
end;
ICompare = interface
function Compare(const ALeft, ARight: Int8): Integer;
end;
PComparerVMT = ^TComparerVMT;
TComparerVMT = packed record
QueryInterface: CodePointer;
_AddRef: CodePointer;
_Release: CodePointer;
Compare: CodePointer;
end;
TCompare = class
class function Int8(const ALeft, ARight: Int8): Integer;
end;
const
{ please note that while this uses instance methods of TRawInterface this does not necessarily
mean that a TRawInterface instance is passed in; e.g. the code in Generics.Defaults uses
a different type as Self that contains the reference count for those types where the
reference count is necessary }
Comparer_Int8_VMT : TComparerVMT = (QueryInterface: @TRawInterface.QueryInterface; _AddRef: @TRawInterface._AddRef; _Release: @TRawInterface._Release; Compare: @TCompare.Int8);
Comparer_Int8_Instance : Pointer = @Comparer_Int8_VMT;
function TInterface.QueryInterface(constref IID: TGUID; out Obj): HResult; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
Result := E_NOINTERFACE;
end;
function TRawInterface._AddRef: LongInt; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
Result := -1;
end;
function TRawInterface._Release: LongInt; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
Result := -1;
end;
class function TCompare.Int8(const ALeft, ARight: Int8): Integer;
begin
Result := ALeft - ARight;
end;
var
intf: ICompare;
begin
intf := ICompare(@Comparer_Int8_Instance);
Writeln(intf.Compare(2, 4));
Writeln(intf.Compare(4, 2));
Writeln(intf.Compare(4, 4));
end.
(*
<postscript>
Look at the Generics.Collections unit he mentioned, and find stuff like " // IComparer VMT"
=> constructing the interface without the compiler (if you know the memory layout that the compiler expects....)
An interface is (simplified) a jump table (a VMT), and maybe some data. So putting together your own VMT, then it can have any code pointer, as long as the code they point to, matches the method signatures in the interface. But this "any code" then does not need to go to an object/instance...
I have not checked, but there may also be code to inject those "interfaces" into classes, so that "SomeClass as IThisInterface" will return such an interface. And then such an interface, despite being returned by that class, has no link to that class.
</postscript>
*)