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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With