I want to write a TCheckBox
and TRadioButton
descendants having 3 identical methods.
TMyCheckBox = class(TCheckBox)
procedure DoS
You are looking for implementation inheritance rather than interface inheritance. This is only achievable in Delphi if you can derive classes from a single common ancestor. This limitation is inherent because the language only supports single-inheritance.
The best you can do is something like this:
type
TMyWinControlExtender = class
private
FTarget: TWinControl;
public
constructor Create(Target: TWinControl);
procedure WMSize(var Message: TWMSize; out CallInherited: Boolean);
procedure DoSomething;
end;
TMyCheckBox = class(TCheckBox)
private
FExtender: TMyWinControlExtender;
protected
procedure WMSize(var Message: TWMSize); message WM_SIZE;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DoSomething;
end;
TMyRadioButton = class(TRadioButton)
private
FExtender: TMyWinControlExtender;
protected
procedure WMSize(var Message: TWMSize); message WM_SIZE;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DoSomething;
end;
{ TMyWinControlExtender }
constructor TMyWinControlExtender.Create(Target: TWinControl);
begin
inherited Create;
FTarget := Target;
end;
procedure TMyWinControlExtender.WMSize(var Message: TWMSize; out CallInherited: Boolean);
begin
if FTarget.... then
....
CallInherited := ...;
//etc.
end;
procedure TMyWinControlExtender.DoSomething;
begin
if FTarget.... then
....
//etc.
end;
{ TMyCheckBox }
constructor TMyCheckBox.Create(AOwner: TComponent);
begin
inherited;
FExtender := TMyWinControlExtender.Create(Self);
end;
destructor TMyCheckBox.Destroy;
begin
FExtender.Free;
inherited;
end;
procedure TMyCheckBox.DoSomething;
begin
FExtender.DoSomething;
end;
procedure TMyCheckBox.WMSize(var Message: TWMSize);
var
CallInherited: Boolean;
begin
FExtender.WMSize(Message, CallInherited);
if CallInherited then
inherited;
end;
And likewise for TMyRadioButton
etc.
Now, you could use interfaces and delegation to reduce some of the boilerplate, but there's no way for that to help with a message handler like WMSize
.
Define an interface say IDoSomething
with the the three method signatures.
Then change your class declaration to
TMyCheckBox = class(TCheckBox, IDoSomething)
and then implement.
If the implementations are common or very close.
Then define a helper class TDoSomething
and then delegate the work.
e.g.
Procedure TMyCheckBox.DoSomething1; // implements IDoSomething1
Begin
TDoSomething.DoSomething1(Self); // given class method will suffice.
End;
Class Methods in delphi, equivalent to static methods in other languages.
Type
TDoSomethingHelper = Class(TObject)
Public
Class Procedure DoSomething1(aComponent : TComponent);
End;
...
implementation
Class Procedure TDoSomethingHelper.DoSomething1(aComponent : TComponent);
Begin
aComponent.Tag = 27;
End;