Delphi Interface Mechanism Truth

Source: Internet
Author: User

 Delphi interface Mechanism TruthCategory: DELPHI2012-03-29 14:41 2161 People read comments (0) favorite reports Delphiinterfaceintegerstringclassfunction

Interface (interface) is a very interesting thing in Delphi. Delphi 3 began to support the interface, which formed the basis of COM programming, however, the interface in Delphi can also be used in non-COM development, the implementation of similar abstract classes (containing abstract methods of the Class), so as to compensate for the Delphi can not be more inheritance (subclass has multiple sibling parent class). The interface described here and the interface part of a unit are completely different concepts, do not confuse.

For a long while, it seems that there is no problem solving the interface. An interface is an agreement between the implementation of a set of functions and the user. When I see the need to implement a set of functions, but the way it is implemented is not deterministic and there are many ways to define the interface. The interface does not care about the specific implementation process of the function, but specifies the input conditions and output results required by the function.

That is, the interface specifies the definition of the function, but it must be implemented by the class. Therefore, the concept of an interface is similar to the pure virtual class of C + +.

This book is a section of the train to tell the interface, so that you understand the real meaning of the interface in Delphi. In the development of this book, the application of the interface is basically not involved.

As an example:
Type
Ishowstring = Interface (IUnknown)
Procedure showstring (s:string);
End

Tiobject = Class (TObject, Ishowstring)
Procedure showstring (s:string);
End

The above code first defines an interface ishowstring, which declares a method showstring. The class Tiobject inherits from TObject and implements the interface ishowstring.


A class can implement one or more interfaces at the same time, such as:
Tiobject = Class (TObject, I1, I2, I3);

The hierarchical relationship of an interface is similar to a class. IUnknown are the ancestors of interfaces, just like the tobject of a class. The following statement:
Type
Toneobject = Class
End

Toneinterface = interface

End

Represents toneobject derived from TObject, Toneinterface derived from IUnknown. An interface cannot have more than one sibling parent interface at the same time.

In the following sections, I want to show the specifics of the interface from different angles.

1. Differences between interfaces and classes

(1) There are only methods, properties, and no fields in the interface. Therefore, the property access in the interface must pass the method.

(2) The method in the interface is only declared and not implemented. The implementation is completed in the class.

(3) The method in the interface has no scope. are public, but are placed in different scopes in the class.

(4) The method in the interface has no modifier words. They can be thought of as abstract.

(5) You cannot create an interface instance, and to use an interface, you must implement it in the class, calling the method of the interface through the class.

(6) All methods of the interface must be declared and implemented in the class. Unlike class inheritance, you can choose.

(7) When the method in the interface is implemented in a class, it can be virtual/dynamic, abstract, and thus can be overridden in subclasses. Such as:



Type
Ishowstring = Interface (IUnknown)
Procedure showstring (s:string);
End

TComponent1 = Class (Tcomponent, Ishowstring)
Protected
Procedure showstring (s:string); Virtual
End

TComponent2 = Class (TComponent1)
Protected
Procedure showstring (s:string); Override
End



2. Interface designation
The typical syntax for declaring an interface is:
Childinterface = Interface (parentinterface)
[' {GUID} ']
{Method List}
End



The [' {GUID} '] (globally unique Identifier, the globally unique indicator) is called interface labeling. A COM class can have a GUID flag. This way we can get the corresponding interface or COM class (instance) through the GUID. The interface designation is not required. In an IDE environment, you can either generate a GUID by pressing the CTRL+SHIFT+G key, or you can call the API function CoCreateGuid get it. If the parent interface is defined and its subinterface is undefined, the label does not inherit to the sub-interface, at which point the subinterface is considered not to be marked. Delphi's Sysutils unit provides a conversion function between the GUID and string stringtoguid, guidtostring.

3. Ancestor IUnknown (System unit)

IUnknown is stated in this way:
IUnknown = IInterface;
IInterface = interface
[' {00000000-0000-0000-c000-000000000046} ']
function QueryInterface (const IID:TGUID; out OBJ): HResult; stdcall;
function _addref:integer; stdcall;
function _release:integer; stdcall;
End

It declares three methods, all of which are used internally. The function is to implement interface count and interface separation.

According to the above-mentioned "interface and class of different" 6th, we know that any class to implement the interface, it must implement the above three methods (of course, when implementing multiple interfaces, three methods need only one implementation). Isn't that a lot of trouble? Fortunately, Delphi internally automatically implements these three methods, so:

(1) If your class derives from TObject and tpersistent, use Tinterfacedobject and tinterfacedpersistent respectively instead of TObject, tpersistent, which implement these three methods internally. Such as:

Tiobject = Class (Tinterfacedobject, Ishowstring)

(2) Tcomponent has directly implemented these three methods:

Tcomponent = Class (Tpersistent, IInterface,

Iinterfacecomponentreference)

Protected

{IInterface}

function QueryInterface (const IID:TGUID; out OBJ): HResult;
Virtual stdcall;

function _addref:integer; stdcall;

function _release:integer; stdcall;

End



Therefore, classes derived from Tcomponent and its subclasses can implement any interface without having to consider the implementation of these three methods.

4. Invocation of the interface method
(1) Direct distribution. Such as:
Var
ishowstr:ishowstring;
Begin

{Classes and the interfaces they implement are compatible}
ISHOWSTR: = Tcomponent2.create (nil);
Ishowstr.showstring (' DD ');

The {interface reference count method eventually destroys the object to which the interface belongs, so you do not need to explicitly destroy the object. We will detail below
Tell the question. }
End



(2) Use the Tobject.getinterface method. When using this method, the interface must have an indication specified. Defined as follows:
function getinterface (const IID:TGUID; out OBJ): Boolean;

Calls such as:
Var
ishowstr:ishowstring;
Begin
Tcomponent2.create (nil). GetInterface (ishowstring, ISHOWSTR);
Ishowstr.showstring (' DD ');
End



(3) Use the RTTI as operator. At this point the interface must also specify a label. Such as:
Begin
(Tcomponent2.create (nil) as ishowstring). Showstring (' DD ');
End



(4) If the class declares an interface method in the public domain, it can invoke the interface method directly with the class instance, at which point there is no difference between the interface side and the method of the class itself.

You can use the following method to determine whether an interface, object, class supports an interface:

function Supports (const instance:iinterface; const IID:TGUID;
Out Intf): Boolean; overload;

function Supports (const instance:tobject; const IID:TGUID;
Out ntf): Boolean; overload;

function Supports (const aclass:tclass; const IID:TGUID): Boolean;
overload;

5. Interface reference count

The interface reference count is implemented by _addref and _release. There is an integer field (such as Tinterfacedobject.refcount) in the class that implements both methods. When referencing an interface, _ADDREF will refcount plus 1, and _release will refcount minus 1 after the reference is complete. If RefCount is reduced to 0 o'clock, _release destroys the object by invoking the Destroy method of the object to which the interface belongs. Let's look at an example:



Var

Obj:tcomponent2;

ishowstr:ishowstring;

Begin

OBJ: = Tcomponent2.create (nil);

ISHOWSTR: = OBJ;

Obj.free;

Ishowstr.showstring (' DD ');

End



When the last sentence is finished, an exception is triggered. Since the Ishowstr method call is complete, _release RefCount is reduced to 0, so Obj.destroy is called, but at this point obj has been destroyed, and thus an exception.

Interface references can be automatically counted and do not need to be explicitly destroyed, but in some real-time programs, you can explicitly destroy an instance of an interface using a format similar to the following:

ISHOWSTR: = nil;

But it doesn't mean that the objects we create can be destroyed without explicitly calling free, Freeandnil, and so on. The internal of the reference count implementation is actually very complex, and we should explicitly destroy dynamically created objects.

6. Method resolution

If a class implements multiple interfaces, and those interfaces have a method of the same name, how should these interfaces be differentiated?

(1) If the principle of overloading is met (the method name is the same, but the parameter is different or one is a procedure, the other is a function), you can declare it as an overloaded method with the overload keyword.

(2) if the exact same. You need to use a method resolution clause. For example:



Type

IShowString1 = Interface (IUnknown)

Procedure showstring (s:string);

End



IShowString2 = Interface (IUnknown)

Procedure showstring (s:string);

End



TComponent1 = Class (Tcomponent, IShowString1, IShowString2)

Protected

{The following two lines are method-resolved clauses}

Procedure ishowstring1.showstring = ShowString1;

Procedure ishowstring2.showstring = ShowString2;



Procedure ShowString1 (s:string);

Procedure ShowString2 (s:string);

End

7. Interface Authorization

Assuming that TComponent1 implements the interface ishowstring, now TComponent2 also needs to implement ishowstring, and the function is exactly the same as TComponent1, Is it possible to refer to this feature from TComponent1 in a very simple way, without having to re-transcribe the code?

Delphi provides the attribute keyword implements to implement this reference function, called proxy or authorization. This is probably what it means:



Type

Ishowstring = Interface (IUnknown)

Procedure showstring (s:string);

End



TComponent1 = Class (Tcomponent, Ishowstring)

Procedure showstring (s:string);

End



TComponent2 = Class (Tcomponent, Ishowstring)

ishowstr:ishowstring;

{The following sentence can replace the declaration showstring}

Property Showstr:ishowstring read ISHOWSTR implements ishowstring;

End



The interface method can then be referenced through the property showstr. However, the ISHOWSTR must be instantiated before the reference. For example:



Constructor Tcomponent2.create (aowner:tcomponent);

Begin

inherited;

ISHOWSTR: = Tcomponent1.create (Aowner);

End



Procedure Tform1.button1click (Sender:tobject);

Var

Component2:tcomponent2;

Begin

Component2: = Tcomponent2.create (nil);

Component2.ShowStr.ShowString (' DD ');

End

Summary
This section describes the concept, role, implementation, and use of the interface in Delphi. There are two purposes for introducing an interface:

(1) The multi-inheritance relationship of simulation class;

(2) Developing COM programs.

In the VCL class library, there are some basic classes (such as tcomponent) and Web classes (such as tmultimodulewebappservices) that use interfaces to help implement some functionality. It is used extensively in COM classes, such as Tinterfacedobject, Tcontainedobject, and so on.

In general, when developing non-COM programs, because there is less need to use multiple inheritance features, the interface is also less used, especially when extending user-defined classes and components from existing VCL classes and components.

Although Delphi is very good, but at present is not popular, so the relevant information is relatively small, before I also spent a lot of time to get the income.

For the convenience of the peers, there is time I will have some experience here and share with you.


Used to know that the use of the interface under the Delphi WIN32 is a bit complicated. The interface is typically implemented by inheriting Tinterfacedobject, while the Tinterfacedobject subclass instance is automatically managed by Delphi based on the reference count. A little attention, it is easy to appear abnormal.


Therefore, the use of Delphi interface to pay attention to the following things:

1. When using interface variables, such as: P:interface, pay attention to the lifetime of P.

p, defined within the method, is the end of the life of P, at the end of the method execution.

Defines the global p, which is the end of the lifetime of P only when the app exits.

When you define p as a property within a class, p is exhausted only if the instance of the class is released.


So if the object referenced by P is released before the end of the life of P, it is easy to see some inexplicable anomalies.

Of course, you can p:=nil after using the P, is a good habit.

2. For expressions: (object as Interface). Method (..), you can assume that Delphi produces a local interface variable, so if the object is released before this local range exits, an exception is triggered when the local scope exits. The solution is: P: = Object as interface, explicit use of interface variables, run out is set to nil.

3. Try to use the interface as a parameter. For example: Define a Process procedure AAA (const p:interface), and if used: AAA (Ttestclass.create (..)), then it is sure to cause a memory leak.

Instances of 4.TInterfacedObject and its subclasses, if not assigned to any interface variables after creation, need to be released manually.



Here are two classes that may be useful to you.

1.TCommonInterfaced. Inherited it can be implemented interface, the feature is to shield Delphi Automatic Management, by the developer to manually manage the release of the instance.

2.TEventInterfaced. Inheriting it can implement the interface, the feature is that after activating the auto-release function of the instance, the actual meeting is released by Delphi when the external use is finished, and released manually if the auto-release function is not activated. This class is primarily used in the event model, similar to the Java event model, where the listener is hung on the event source as an interface, and the listener can be freed only when the event source is revoked. So, if the listener is inherited from teventinterfaced, then the event source activates the listener's auto-release function before it is revoked, so Delphi can choose the appropriate time to release the listener.



The source code is as follows:


********************************************************************

Unit eubase;


Interface
Uses classes,sysutils;


Type

An ordinary interface object. Objects are not freed automatically when the interface is no longer in use.
tcommoninterfaced = Class (Tinterfacedobject)
Protected
function _addref:integer; stdcall;
function _release:integer; stdcall;
Public
Procedure Afterconstruction; Override
Procedure Beforedestruction; Override
End

An interface object that is dedicated to the event model.
So when you need to release an object that implements an interface, as long as the auto-release function of the interface is activated, the object is automatically freed when the interface is not used
Ieventinterface = Interface (iinterface)
[' {4a8c144e-07b9-4357-8bf0-ee57d2f69888} ']
Procedure Releaseinidle;
End

{
An interface object that is dedicated to the event model.
When you need to release an object that implements an interface, as long as the auto-release function of the interface is activated,
Object is freed automatically when the interface is not used.
}
teventinterfaced = Class (Tinterfacedobject, Ieventinterface)
Private
Mautorelease:boolean;
Procedure Releaseinidle;
Protected
function _addref:integer; stdcall;
function _release:integer; stdcall;
Public
Procedure Afterconstruction; Override
Procedure Beforedestruction; Override
End



Implementation

{Tcommoninterface}

{
tcommoninterfaced *******************************
}
Procedure Tcommoninterfaced.afterconstruction;
Begin

End

Procedure Tcommoninterfaced.beforedestruction;
Begin

End

function Tcommoninterfaced._addref:integer;
Begin
Result:=1;
End

function Tcommoninterfaced._release:integer;
Begin
Result:=1;
End

{Teventinterface}

{
teventinterfaced *******************************
}
Procedure Teventinterfaced.afterconstruction;
Begin
inherited;
Mautorelease:=false;
End

Procedure Teventinterfaced.beforedestruction;
Begin
inherited;

End

Procedure Teventinterfaced.releaseinidle;
Begin
Mautorelease:=true;
End

function Teventinterfaced._addref:integer;
Begin
if (refcount=0) and (Mautorelease=false) then inherited _addref ();
Result:=inherited _addref ();
End

function Teventinterfaced._release:integer;
Begin
if (refcount=2) and (mautorelease=true) then
Begin
Inherited _release ();
Result:=inherited _release ();
End
else if (refcount<>1) or (mautorelease=true) then
Result:=inherited _release ()
Else
Result:=inherited _release ();
End

End.


*******************************************************************

The unit of use may need to be supplemented because the source code is an excerpt.

Delphi Interface Mechanism Truth

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.