RAD Studio (Common)
ContentsIndex
PreviousUpNext
Interface References

If you declare a variable of an interface type, the variable can reference instances of any class that implements the interface. These topics describe Interface references and related topics.

Interface reference variables allow you to call interface methods without knowing at compile time where the interface is implemented. But they are subject to the following:

  • An interface-type expression gives you access only to methods and properties declared in the interface, not to other members of the implementing class.
  • An interface-type expression cannot reference an object whose class implements a descendant interface, unless the class (or one that it inherits from) explicitly implements the ancestor interface as well.
For example,

type
    IAncestor = interface
end;
IDescendant = interface(IAncestor)
    procedure P1;
end;
TSomething = class(TInterfacedObject, IDescendant)
    procedure P1;
    procedure P2;
end;
    .
    .
    .
var
    D: IDescendant;
    A: IAncestor;
begin
    D := TSomething.Create;  // works!
    A := TSomething.Create;  // error
    D.P1;  // works!
    D.P2;  // error
end;

In this example, A is declared as a variable of type IAncestor. Because TSomething does not list IAncestor among the interfaces it implements, a TSomething instance cannot be assigned to A. But if we changed TSomething's declaration to

TSomething = class(TInterfacedObject, IAncestor, IDescendant)
.
.
.

the first error would become a valid assignment. D is declared as a variable of type IDescendant. While D references an instance of TSomething, we cannot use it to access TSomething's P2 method, since P2 is not a method of IDescendant. But if we changed D's declaration to

D: TSomething;

the second error would become a valid method call. 

On the Win32 platform, interface references are typically managed through reference-counting, which depends on the _AddRef and _Release methods inherited from IInterface. Using the default implementation of reference counting, when an object is referenced only through interfaces, there is no need to destroy it manually; the object is automatically destroyed when the last reference to it goes out of scope. Some classes implement interfaces to bypass this default lifetime management, and some hybrid objects use reference counting only when the object does not have an owner. 

Global interface-type variables can be initialized only to nil

To determine whether an interface-type expression references an object, pass it to the standard function Assigned.

Variables of a given class type are assignment-compatible with any interface type implemented by the class. Variables of an interface type are assignment-compatible with any ancestor interface type. The value nil can be assigned to any interface-type variable. 

An interface-type expression can be assigned to a variant. If the interface is of type IDispatch or a descendant, the variant receives the type code varDispatch. Otherwise, the variant receives the type code varUnknown

A variant whose type code is varEmpty, varUnknown, or varDispatch can be assigned to an IInterface variable. A variant whose type code is varEmpty or varDispatch can be assigned to an IDispatch variable.

An interface-type expression can be cast to Variant. If the interface is of type IDispatch or a descendant, the resulting variant has the type code varDispatch. Otherwise, the resulting variant has the type code varUnknown

A variant whose type code is varEmpty, varUnknown, or varDispatch can be cast to IInterface. A variant whose type code is varEmpty or varDispatch can be cast to IDispatch.

You can use the as operator to perform checked interface typecasts. This is known as interface querying, and it yields an interface-type expression from an object reference or from another interface reference, based on the actual (runtime) type of the object. An interface query has the form

object as interface

where object is an expression of an interface or variant type or denotes an instance of a class that implements an interface, and interface is any interface declared with a GUID. 

An interface query returns nil if object is nil. Otherwise, it passes the GUID of interface to the QueryInterface method in object, raising an exception unless QueryInterface returns zero. If QueryInterface returns zero (indicating that object's class implements interface), the interface query returns an interface reference to object.

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!