I want to write a TCheckBox and TRadioButton descendants having 3 identical methods.
TMyCheckBox = class(TCheckBox)
  procedure DoSomething1;
  procedure DoSomething2;
  procedure WMSize(var Message: TWMSize); message WM_SIZE;
end;
TMyRadioButton = class(TRadioButton)
  procedure DoSomething1;
  procedure DoSomething2;
  procedure WMSize(var Message: TWMSize); message WM_SIZE;
end;
// the following procedures are common for both classes, so in fact
// TMyCheckBox.DoSomething1 do the same as TMyRadioButton.DoSomething1
procedure DoSomething1;
begin
  // here is the same code for TMyCheckBox as well as for TMyRadioButton
  // but I don't want to write the same code many times but implement it
  // for both classes at once in some common way
end;
procedure DoSomething2;
begin
  // here is the same code for TMyCheckBox as well as for TMyRadioButton
  // but I don't want to write the same code many times but implement it
  // for both classes at once in some common way
end;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
begin
  // here is the same code for TMyCheckBox as well as for TMyRadioButton
  // but I don't want to write the same code many times but implement it
  // for both classes at once in some common way
end;
How can I do this?
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;
                        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.
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