继承类覆盖虚方法依赖项

Zig*_*giZ 10 delphi delphi-7

我有这两个班:

type
  TMyBaseClass = class
  protected
    FAllowDoSomething: Boolean; // initialized to False
    procedure DoSomething; virtual;
  end;

  TMyChildClass = class(TMyBaseClass)
  protected
    procedure DoSomething; override;
  end;

implementation

procedure TMyBaseClass.DoSomething;
begin
  if not FAllowDoSomething then Exit; // Abort;
  ShowMessage('TMyBaseClass: FAllowDoSomething is False. You wont see me!');
end;

procedure TMyChildClass.DoSomething;
begin
  inherited; // Must inherit
  // if not FAllowDoSomething then Exit; { I don't want to check here again }
  ShowMessage('TMyChildClass: FAllowDoSomething is False but still I can see this message!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TMyBaseClass.Create do try
    DoSomething;
  finally
    Free;
  end;    

  // if I use Abort in TMyBaseClass, the code will not get here

  with TMyChildClass.Create do try
    DoSomething;
  finally
    Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

TMyChildClass.DoSomething我必须inherited,TMyBaseClass.DoSomething但我希望它尊重if not FAllowDoSomething then <don't do anything>.

我已经尝试使用AbortTMyBaseClass,但我意识到这不是一个好主意,将打破调用方法(TForm1.Button1Click);

什么是这样做的,没有写的正确的做法if not FAllowDoSomething then Exit 再次TMyChildClass.

Dav*_*nan 11

关键是在基类中对布尔值执行一次检查.所以,让DoSomething非虚拟化并在你的基类中实现它,如下所示:

procedure TMyBaseClass.DoSomething;
begin
  if FAllowDoSomething then
    DoSomethingImplementation;
end;
Run Code Online (Sandbox Code Playgroud)

其中DoSomethingImplementation是您在派生类中重写的虚方法.

然后基类看起来像这样:

type
  TMyBaseClass = class
  private
    FAllowDoSomething: Boolean;
  protected
    procedure DoSomethingImplementation; virtual;
  public
    procedure DoSomething;
  end;
Run Code Online (Sandbox Code Playgroud)

派生类看起来像这样:

type
  TMyDerivedClass = class(TMyBaseClass)
  protected
    procedure DoSomethingImplementation; override;
  end;
Run Code Online (Sandbox Code Playgroud)

您重写的方法如下所示:

procedure TMyDerivedClass.DoSomethingImplementation;
begin
  inherited;
  ShowMessage(...);
end;
Run Code Online (Sandbox Code Playgroud)

  • +1如果您希望基类在子类代码之前和/或之后执行某些操作,那么这是一种非常常见的模式.通常这些方法对称为`Foo`(非虚拟)和`DoFoo`(虚拟) (4认同)
  • 是的,命名.我被你选择的DoSomething所束缚.不想写DoDoSomerthing. (2认同)