вторник, 2 июня 2020 г.

Перегруженный protected constructor. Bug or expected behavior?


По работе захотел воспользоваться паттерном фабричный метод, и спрятать конструктор за protected декларацию.

program ProtectedConstructor;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

  type
    TBaseClass = class
    protected
      FData : string;
      constructor Create(const AData: string); virtual;
    public
      class function FactoryMethod(const Adata: string): TBaseClass;
      property Data : string read FData;
    end;

  type
    TInheritor = class (TBaseClass)
    protected
      constructor Create(const AData: string); override;
    end;

constructor TBaseClass.Create(const AData: string);
begin
  Fdata := Adata;
  Writeln('TBaseClass.Create');
end;

class function TBaseClass.FactoryMethod(const Adata: string): TBaseClass;
begin
  Result := TInheritor.Create(Adata)
end;

constructor TInheritor.Create(const AData: string);
begin
  inherited;
  Writeln('TInheritor.Create');
end;

var
  MyClass : TBaseClass;

begin
  try
    MyClass := TBaseClass.FactoryMethod('Test');
    try
      Writeln(MyClass.Data);
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    MyClass.Free;
    Readln;
  end;
end.

Ожидаемое поведение:

Я же решил разнести классы по разным модулям. TBaseClass в одном, и TInheritor в другом.


program BugProtectedConstructor;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  uBaseClass in 'uBaseClass.pas',
  uInheritor in 'uInheritor.pas';

var
  MyClass : TBaseClass;

begin
  try
    MyClass := TBaseClass.FactoryMethod('Test');
    try
      Writeln(MyClass.Data);
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    MyClass.Free;
    Readln;
  end;
end.
unit uBaseClass;

interface

  type
    TBaseClass = class
    protected
      FData : string;
      constructor Create(const AData: string); virtual;
    public
      class function FactoryMethod(const Adata: string): TBaseClass;
      property Data : string read FData;
    end;

implementation

uses
  uInheritor;

constructor TBaseClass.Create(const AData: string);
begin
  Fdata := Adata;
  Writeln('TBaseClass.Create');
end;

class function TBaseClass.FactoryMethod(const Adata: string): TBaseClass;
begin
  Result := TInheritor.Create(Adata)
end;

end.
unit uInheritor;

interface

uses
  uBaseClass;

  type
    TInheritor = class (TBaseClass)
    protected
      constructor Create(const AData: string); override;
    end;

implementation

{ TInheritorOne }

constructor TInheritor.Create(const AData: string);
begin
  inherited;
  Writeln('TInheritor.create');
end;
end.



На выходе:


То есть в перегруженный конструктор мы не попадаем.
И вот вопрос, это баг или фича?
Запостил в quality portal
https://quality.embarcadero.com/browse/RSP-29333