I saw a code like this the other day:
type
TcxGridTableControllerAccess = class (TcxGridTableController);
TMycxGridDBTableView = class (TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class (TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class (TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class (TMycxGridDBTableView);
TMycxGridDBTableView inherited from TcxGridDBTableView that inherited from TMycxGridDBTableView. Searched for Cyclic Inheritance but only Java results.
What is this called?
Ps: I don't have the full buildable code with me.
The example code doesn't do what you think it does. You see TMycxGridDBTableView being defined as a descendant of TcxGridDBTableView, and then you see TcxGridDBTableView, defined as a descendant of TcxGridDBTableView.
However, the TcxGridDBTableView you see at the top is not the same TcxGridDBTableView that you see later. The first one refers to a class declared elsewhere, in some other unit. The next occurrence is declaring a new class in this unit that happens to have the same base name as the other unit's class.
This technique is known as an interposer class. It's used to introduce a new GetViewDataClass method, but still end up with the same class name. The form that uses controls with that name will use the new version of the class instead of the original version. It's a way to customize a VCL control without having to compile and install a custom package.
What you show is not cyclic inheritance. What happens is that dxSample.TMycxGridDBTableView inherits from a TcxGridDBTableView in another unit, probably cxGridDBTableView.TcxGridDBTableView. And dxSample.TcxGridDBtableView inherits from dxSample.TMycxGridDBTableView.
Your code is equivalent to:
type
TcxGridTableControllerAccess = class(TcxGridTableController);
{ Note: this does NOT inherit from the TcxGridDBTableView defined }
{ a little further on in the source. It inherits from the original }
{ DevEx TcxGridDBTableView. }
TMycxGridDBTableView = class(cxGridDBTableView.TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class(TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class(TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class(TMycxGridDBTableView);
So the hierarchy is:
cxGridDBTableView.TcxGridDBTableView
|
v
dxSample.TMycxGridDBTableView
|
v
dxSample.TcxGridDBTableView
So dxSample.TMycxGrdiDBTableView does not inherit from dxSample.TcxGridDBTableView, but from cxGridDBTableView.TcxGridDBTableView instead, so there is no so called cyclic inheritance there. The whole misunderstanding comes from the fact that the two classes in the different units have the same name and that the first declaration does not fully qualify the class it is inheriting from.
Now, if someone puts the unit dxSample after cxridDBTableView in his or her uses clause, then dxSample.TCxGridDBTableView is used, instead of the original DevEx class. This is called interposing.
When people want to modify the behaviour of the VCL and FireMonkey, it is not unusual to see interposer classes like
type
TVCLClass = class(OriginalVCLUnit.TVCLClass)
// modifications to the original TVCLClass
end;
or
type
TMyVCLClass = class(OriginalVCLUnit.TVCLClass)
//
end;
TVCLClass = class(TMyVCLCLass);
The code you showed does the latter.
Related
Is it possible to add and implement an interface to an already existing class (which is a descendant of TInterfaced or TInterfacedPersistent) to accomplish separating Model and View into 2 units?
A small explanation why I need something like this:
I am developing a tree-structure, open-type model, which has following structure (VERY simplified and incomplete, just to illustrate the outline of the problem):
Database_Kernel.pas
TVMDNode = class(TInterfacedPersistent);
public
class function ClassGUID: TGUID; virtual; abstract; // constant. used for RTTI
property RawData: TBytes {...};
constructor Create(ARawData: TBytes);
function GetParent: TVMDNode;
function GetChildNodes: TList<TVMDNode>;
end;
Vendor_Specific_Stuff.pas
TImageNode = class(TVMDNode)
public
class function ClassGUID: TGUID; override; // constant. used for RTTI
// Will be interpreted out of the raw binary data of the inherited class
property Image: TImage {...};
end;
TUTF8Node = class(TVMDNode)
public
class function ClassGUID: TGUID; override; // constant. used for RTTI
// Will be interpreted out of the raw binary data of the inherited class
property StringContent: WideString {...};
end;
TContactNode = class(TVMDNode)
public
class function ClassGUID: TGUID; override; // constant. used for RTTI
// Will be interpreted out of the raw binary data of the inherited class
property PreName: WideString {...};
property FamilyName: WideString {...};
property Address: WideString {...};
property Birthday: TDate {...};
end;
Using a GUID-based RTTI (which uses ClassGUID), the function GetChildNodes is able to find the matching class and initialize it with the raw data. (Each dataset contains ClassGUID and RawData beside other data like created/updated timestamps)
It is important to notice that my API (Database_Kernel.pas) is strictly separated from the vendor's node classes (Vendor_Specific_Stuff.pas).
A vendor-specific program's GUI wants to visualize the nodes, e.g. giving them an user-friendly name, an icon etc.
Following idea works:
IGraphicNode = interface(IInterface)
function Visible: boolean;
function Icon: TIcon;
function UserFriendlyName: string;
end;
The vendor's specific descendants of TVMDNode in Vendor_Specific_Stuff.pas will implement the IGraphicNode interface.
But the vendor also needs to change Database_Kernel.pas to implement IGraphicNode to the base node class TVMDNode (which is used for "unknown" nodes, where RTTI was unable to find the matching class of the dataset, so at least the binary raw data can be read using TVMDNode.RawData).
So he will change my class as follows:
TVMDNode = class(TInterfacedPersistent, IGraphicNode);
public
property RawData: TBytes {...};
class function ClassGUID: TGUID; virtual; abstract; // constant. used for RTTI
constructor Create(ARawData: TBytes);
function GetParent: TVMDNode;
function GetChildNodes: TList<TVMDNode>;
// --- IGraphicNode
function Visible: boolean; virtual; // default behavior for unknown nodes: False
function Icon: TIcon; virtual; // default behavior for unknown nodes: "?" icon
function UserfriendlyName: string; virtual; // default behavior for unknown nodes: "Unknown"
end;
The problem is that IGraphicNode is vendor/program-specific and should not be in the API's Database_Kernel.pas, since GUI and Model/API should be strictly divided.
My wish would be that the interace IGraphicNode could be added and implemented to the existing TVMDNode class (which is already a descendant of TInterfacedPersistent to allow interfaces) in a separate unit. As far as I know, Delphi does not support something like this.
Beside the fact that it is not nice to mix Model and View in one single unit/class, there will be following real-world problem: If the vendor has to change my Database_Kernel.pas API to extend TVMDNode with the IGraphicNode interface, he needs to re-do all his changes, as soon as I release a new version of my API Database_Kernel.pas.
What should I do? I thought very long about possible solutions possible with Delphi's OOP. A workaround may be nesting TVMDNode's into a container class, which has a secondary RTTI, so after I have found the TVMDNode class, I could search for a TVMDNodeGUIContainer class. But this sounds very strangle and like a dirty hack.
PS: This API is an OpenSource/GPL project. I am trying to stay compatible with old generations of Delphi (e.g. 6), since I want to maximize the number of possible users. However, if a solution of the problem above is only possible with the new generation of Delphi languages, I might consider dropping Delphi 6 support for this API.
Yes it is possible.
We implemented something similar to gain control of global/singletons for testing purposes. We changed our singletons to be accessible as interfaces on the application (not TApplication, our own equivalent). Then we added the ability to dynamically add/remove interfaces at run-time. Now our test cases are able to plug in suitable mocks as and when needed.
I'll describe the general approach, hopefully you'll be able to apply it to the specifics of your situation.
Add a field to hold a list of dynamically added interface. An TInterfaceList works nicely.
Add methods to add/remove the dynamic interfaces.
Override function QueryInterface(const IID: TGUID; out Obj): HResult; virtual;. Your implementation will first check the interface list, and if not found will defer to the base implementation.
Edit: Sample Code
To answer your question:
I understand that the class now can tell others that it supports interface X now, so the interface was ADDED during runtime. But I also need to IMPLEMENT the interface's methods from outside (another unit). How is this done?
When you add the interface, you're adding an instance of the object that implements the interface. This is very much like the normal property ... implements <interface> technique to delegate implementation of an interface to another object. The key difference being this is dynamic. As such it will have the same kinds of limitations: E.g. no access to the "host" unless explicitly given a reference.
The following DUnit test case demonstrates a simplified version of the technique in action.
unit tdDynamicInterfaces;
interface
uses
SysUtils,
Classes,
TestFramework;
type
TTestDynamicInterfaces = class(TTestCase)
published
procedure TestUseDynamicInterface;
end;
type
ISayHello = interface
['{6F6DDDE3-F9A5-407E-B5A4-CDF91791A05B}']
function SayHello: string;
end;
implementation
{ ImpGlobal }
type
TDynamicInterfaces = class(TInterfacedObject, IInterface)
{ We must explicitly state that we are implementing IInterface so that
our implementation of QueryInterface is used. }
private
FDynamicInterfaces: TInterfaceList;
protected
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
public
constructor Create;
destructor Destroy; override;
procedure AddInterface(AImplementedInterface: IInterface);
end;
type
TImplementor = class (TInterfacedObject, ISayHello)
{ NOTE: This could easily have been implemented in a separate unit. }
protected
{ISayHello}
function SayHello: string;
end;
{ TDynamicInterfaces }
procedure TDynamicInterfaces.AddInterface(AImplementedInterface: IInterface);
begin
{ The simplest, but least flexible approach (see also QueryInterface).
Other options entail tagging specific GUIDs to be associated with given
implementation instance. Then it becomes feasible to check for duplicates
and also dynamically remove specific interfaces. }
FDynamicInterfaces.Add(AImplementedInterface);
end;
constructor TDynamicInterfaces.Create;
begin
inherited Create;
FDynamicInterfaces := TInterfaceList.Create;
end;
destructor TDynamicInterfaces.Destroy;
begin
FDynamicInterfaces.Free;
inherited Destroy;
end;
function TDynamicInterfaces.QueryInterface(const IID: TGUID; out Obj): HResult;
var
LIntf: IInterface;
begin
{ This implementation basically means the first implementor added will be
returned in cases where multiple implementors support the same interface. }
for LIntf in FDynamicInterfaces do
begin
if Supports(LIntf, IID, Obj) then
begin
Result := S_OK;
Exit;
end;
end;
Result := inherited QueryInterface(IID, Obj);
end;
{ TImplementor }
function TImplementor.SayHello: string;
begin
Result := 'Hello. My name is, ' + ClassName;
end;
{ TTestDynamicInterfaces }
procedure TTestDynamicInterfaces.TestUseDynamicInterface;
var
LDynamicInterfaceObject: TDynamicInterfaces;
LInterfaceRef: IUnknown;
LFriend: ISayHello;
LActualResult: string;
begin
LActualResult := '';
{ Use ObjRef for convenience to not declare interface with "AddInterface" }
LDynamicInterfaceObject := TDynamicInterfaces.Create;
{ But lifetime is still managed by the InterfaceRef. }
LInterfaceRef := LDynamicInterfaceObject;
{ Comment out the next line to see what happens when support for
interface is not dynamically added. }
LDynamicInterfaceObject.AddInterface(TImplementor.Create);
if Supports(LInterfaceRef, ISayHello, LFriend) then
begin
LFriend := LInterfaceRef as ISayHello;
LActualResult := LFriend.SayHello;
end;
CheckEqualsString('Hello. My name is, TImplementor', LActualResult);
end;
end.
You can preserve the ability to persist data and implement it through inheritance and still create the correct instances for the ClassGUIDs stored in the tables if you'd apply the factory design pattern.
For each node class there would be one class factory (or just a function pointer) responsible for creation of the correct Delphi class. Class factories may register themselves in the unit initialization section (once per application startup) at the kernel singleton object.
The kernel singleton would then map GUID to correct factory that would in turn call the correct class instance constructor (as shown at http://delphipatterns.blog.com/2011/03/23/abstract-factory)
Packages may be split into separate DLLs and classes implemented in separate units, still inheriting from one base TVMNode class.
The features you now use RTTI for can be supported in descendant classes or in the factory classes easily through some virtual methods.
You might also consider using simpler Data Transfer Objects for saving/loading the TVMNodes and perhaps take some inspiration from an already well perceived Object Relational Mapper or a Object Persistence framework as the problem you are trying to solve seem to me like exactly the problems they are handling (already)
I don't know about good Delphi open source frameworks of this class. But from other languages you can look at Java Hibernate, Microsoft .NET Entity Framework or minimalistic Google Protocol Buffers serializer
I'm new into the Delphi coding and I get an error when trying to override a constructor , can you advice me on what I'm doing wrong or what should I do to get to the desired result.
I want to override the constructor of a frame so that it will chance the Caption of an label it containts to a specific text.
here is the code
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TfrmMesaj = class(TFrame)
Panel1: TPanel;
private
{ Private declarations }
public
{ Public declarations }
constructor Create(name : string); override;
end;
implementation
{$R *.dfm}
{ TfrmMesaj }
{ TfrmMesaj }
constructor TfrmMesaj.Create(name: string);
begin
inherited;
Panel1.Color := clRed;
Panel1.Caption := name;
end;
end.
When I try to compile I get the following errors :
[DCC Error] frameMesaj.pas(17): E2037 Declaration of 'Create' differs from previous declaration
[DCC Error] frameMesaj.pas(32): E2008 Incompatible types
What Am I doing wrong and how can I achive what I want?
Stefan has explained why your override isn't working. Basically, whenever you override a virtual method the signatures of the two methods must match exactly. However, I'm strongly opposed to the use of reintroduce. And I'll explain why at the bottom of this answer. (Please also note that reintroduce quite specifically does not override the ancestor method. It only hides the warning that the method is hiding the ancestor's method.)
A couple of better options:
Use a different name for your constructor
You don't have to name your constructors Create. You could for example add a second constructor as: constructor CreateWithCaption(AName: string);. Note that I didn't even make this constructor virtual. Only make methods virtual if you intend them to behave polymorphically. (Which means you want subclasses to be able to change the implementation even when called from the base class.)
This option is very much like overload as suggested by Stefan.
Use a factory method to create your frame
As systems get larger it can be useful to separate the processing of creating some objects from the work they actually do. This is done using factory methods whose sole purpose is to create other objects that are ready to interact with the rest of your system. E.g.
//I've chosen to demonsrate this on a form, but you could also implement a dedicated factory class
function TMyForm.CreateMessageFrame(ACaption: string): TFrame;
begin
//Note the factory method intends the form to own all frames created.
Result := TfrmMesaj.Create(Self);
//The factory method ensures the frame is "ready"
//This does violate Law of Demeter, but you could easily add a method to the fram to resolve that.
Result.Panel1.Color := clRed;
Result.Panel1.Caption := ACaption;
end;
What's wrong with reintroduce anway?
Reintroduce is only applicable when the method on the base class is virtual.
The method should only be virtual if it's intended to be used polymorphically.
This means that the method is intended to be called from a base class reference, but might need to take special action to work correctly in some subclasses.
Since your question was dealing with overriding TComponent.Create, it will serve very nicely to illustrate by way of example.
constructor TComponent.Create(AOwner: TComponent); is virtual quite specifically so component creation behaves polymorphically. This is so that when components are streamed from a .DFM file they will be created correctly even though the reference used to create them is of type TComponent.
If you hide this constructor, then any special actions you need to take when your frame is streamed and created from a .DFM will not happen.
Also any subclasses of your frame will not be able to override constructor Create(AOwner: TComponent); because it is hidden.
The constructor of TFrame looks like this:
constructor Create(AOwner: TComponent); virtual;
If you want to override it you must keep the signature:
constructor Create(AOwner: TComponent); override;
If you want to add your own version providing a name you need to overload it so that both versions exist side by side:
constructor Create(name: string); reintroduce; overload; // see Edit below
If you want to hide the virtual one you need to write reintroduce (not recommended):
constructor Create(name: string); reintroduce;
Edit:
reintroduce is also needed when you overload a virtual method even without hiding it. This has been reported and discussed here: http://qc.embarcadero.com/wc/qcmain.aspx?d=106026
Why don't you simply use OnCreeate event instead of trying to override default Constructor method.
In your case OnCreate event would be enough since you are not making any critical changes to the TFrame component itself but only to other components that have been placed on it.
I've been trying to extend a bunch of library classes inheriting from the same base class by overriding a virtual method defined in that base class. The modification is always the same so instead of creating N successors of the library classes I decided to create a generic class parameterized by the library class type, which inherits from the class specified by parameter and overrides the base class' method.
The problem is that the code below doesn't compile, the compiler doesn't allow inheriting from T:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
end;
LibraryClassB = class(LibraryBaseClass)
end;
LibraryClassC = class(LibraryBaseClass)
end;
LibraryClassD = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T) //Project1.dpr(20) Error: E2021 Class type required
procedure foo; override;
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure MyClass<T>.foo;
begin
end;
begin
MyClass<LibraryClassA>.Create.foo;
MyClass<LibraryClassB>.Create.foo;
MyClass<LibraryClassC>.Create.foo;
MyClass<LibraryClassD>.Create.foo;
end.
Any ideas how to make this work? Maybe there is a way to trick the compiler into accepting something equivalent because, for example, inheriting from Dictionary<T,T> compiles without problems.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
Thank you
As you've been told already, this is valid with C++ templates, not with C# or Delphi generics. The fundamental difference between templates and generics is that conceptually, each template instantiation is a completely separately compiled type. Generics are compiled once, for all possible types. That simply is not possible when deriving from a type parameter, because you could get constructs such as
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
procedure foo; reintroduce; virtual;
end;
LibraryClassB = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T)
procedure foo; override; // overrides LibraryClass.foo or LibraryClassA.foo ?
end;
Yet this can work in C++, because in C++ MyClass<LibraryClassA> and MyClass<LibraryClassB> are completely separated, and when instantiating MyClass<LibraryClassA>, foo is looked up and found in LibraryClassA before the base class method is found.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
It is possible to create types at runtime, but almost certainly an extremely bad idea. I have had to make use of that once and would have loved to avoid it. It involves reading the VMT, creating a copy of it, storing a copy of the original LibraryBaseClass.foo method pointer somewhere, modifying the VMT to point to a custom method, and from that overriding function, invoking the original stored method pointer. There's certainly no built-in language support for it, and there's no way to refer to your derived type from your code.
I've had a later need for this in C# once, too, but in that case I was lucky that there were only four possible base classes. I ended up manually creating four separate derived classes, implementing the methods four times, and using a lookup structure (Dictionary<,>) to map the correct base class to the correct derived class.
Note that there is a trick for a specific case that doesn't apply to your question, but may help other readers: if your derived classes must all implement the same interface, and requires no new data members or function overrides, you can avoid writing the implementation multiple times:
type
IMySpecialInterface = interface
procedure ShowName;
end;
TMySpecialInterfaceHelper = class helper for TComponent
procedure ShowName;
end;
procedure TMySpecialInterfaceHelper.ShowName;
begin
ShowMessage(Name);
end;
type
TLabelWithShowName = class(TLabel, IMySpecialInterface);
TButtonWithShowName = class(TButton, IMySpecialInterface);
In that case, the class helper method implementation will be a valid implementation for the interface method.
In Delphi XE and higher, you could also try something completely different: TVirtualMethodInterceptor.
What you are attempting to do is simply not possible with Delphi generics.
For what it is worth, the equivalent code is also invalid in C# generics. However, your design would work with C++ templates.
I probably misunderstood your description of the problem but from your simplified example it seems you could "turn it around" and insert a class in the hierarchy in the middle like this:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryBaseFooClass = class(LibraryBaseClass)
procedure foo; override;
end;
LibraryClassA = class(LibraryBaseFooClass)
end;
LibraryClassB = class(LibraryBaseFooClass)
end;
LibraryClassC = class(LibraryBaseFooClass)
end;
LibraryClassD = class(LibraryBaseFooClass)
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure LibraryBaseFooClass.foo;
begin
end;
begin
LibraryClassA.Create.foo;
LibraryClassB.Create.foo;
LibraryClassC.Create.foo;
LibraryClassD.Create.foo;
end.
I come from a vb/c# background and I am having difficulty understanding the meaning of part of the following code, specifically the bit 'self.fColConsignments.Add'
TConsignment = class(TCollectionItem)
constructor Create(Collection : TCollection); override;
...
function TIFCSUMMsg.AddConsignment: TConsignment;
begin
result := TConsignment(self.fColConsignments.Add);
end;
if you background is C#, don't missinterpret that line:
result := TConsignment(self.fColConsignments.Add);
it's just a type cast and not a constructor call. In C# it would look like:
result = (TConsignment)self.fColConsignments.Add;
Presumably fcolConsignments is a collection owned by the TIFCSUMMsg instance (Self). Add adds a new item to the collection and returns the reference as the result. The result is then cast to a TConsignment to fit the result type of the AddConsignment method.
self.fColConsignments.Add probably adds a new item into fColConsignments, which must be a collection or similar, and returns it. But the declared return type may be more generic than the actual object returned, then a typecast is applied by using TConsignment(object).
The code in your example IS NOT A CONSTRUCTOR.
In C++/C#/Java/(put your C descendant language here), constructors are nameless methods. So:
class TFoo {
TFoo() { // do something }
}
....
{
TFoo myFoo;
myFoo = new TFoo()
.....
}
This a typical construction on such languages. This is NOT how Delphi works.
Constructors in Delphi have names. The convention is that they are called .Create and
they can be static or virtual ones (like any method).
The code above can be converted to:
TFoo = class
constructor Create();
end;
...
constructor TFoo.Create()
begin
// Do something;
end;
....
// Creating an object
var
myFoo: TFoo;
begin
myFoo := TFoo.Create();
...
end;
The code you exemplified were not an constructor but a
kind of typecast.
You can get more information about this (typecasts and constructors)
in the Delphi Language Guide (or Object Pascal Language Guide, depending
on the Delphi version you have available).
I have a persistence framework, and I am trying to use generics so I don't have to keep creating new list classes for each type of object I want to store in a type safe way.
I have a method that returns the class of the contained object in the list class (so I know which queries to run and which object to create.
As an example, it looks something like this:
type
TMyObject = class
end;
TMyObjectClass = class of TMyObject;
TMyObjectList = class
public
function ListClass: TMyObjectClass; virtual; abstract;
end;
TMyObjectList<T: TMyObject, constructor> = class(TMyObjectList)
public
function ListClass: TMyObjectClass; override;
end;
implementation
{ TMyObjectList<T> }
function TMyObjectList<T>.ListClass: TMyObjectClass;
begin
result := T; // <==== this wont compile
end;
end.
Is there a way of returning the class of the generic parameter in this case?
Thanks
N#
(using Delphi 2009)
This is a known issue in Delphi 2009. It's been fixed in 2010. I just tested it and your code compiles just fine there.
T is not an instance of an object.
In your specific example, you should write something like:
result := self;
I think you're looking the wrong way...