一般继承 /虚方法 跳过父类执行 祖父类的方法

背景:某一天不小心把基类函数写成了 虚函数virtual,子类override 重写时,有同事需要跳过父类执行祖父类的方法代码;

  发现  T祖父类(self).**方法(),时异常。因为虚函数转型为祖父类时,是多态的形式,还是会执行本子类的方法,所有造成一种循环执行代码,造成栈溢出  ;

网上百度到 hack的函数 找到祖父类的方法基地址 执行。

解决一:不用虚方法,一般的继承即可。

unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type
  TMyClassA=class(TStringList)
  public
    procedure KKK();// virtual;
  end;
  TMyClassB=class(TMyClassA)
  public
    procedure KKK();//override;
  end;
  TMyClassC=class(TMyClassB)
  public
    procedure KKK(); //override;
  end;
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
    A:TMyClassA;
    B:TMyClassB;
    C:TMyClassC;
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyClassA.KKK();
begin
  ShowMessage('TMyClassA.KKK');
end;
procedure TMyClassB.KKK();
begin
  inherited;
  ShowMessage('TMyClassB.KKK');
end;
procedure TMyClassC.KKK();
begin
  //inherited; 注释后  不就不执行 TMyClassB.KKK()
 // TMyClassA(self).KKK;
  ShowMessage('TMyClassC.KKK');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
    A:=TMyClassA.Create ;
    B:=TMyClassB.Create;
    C:=TMyClassC.Create;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  A.KKK;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  B.KKK;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
  C.KKK;
end;
end.

解决二:虚拟方法跳过父类继承调用祖父类的代码  http://blog.csdn.net/coolbaby/article/details/485652

  此方法已经本人亲自验证过,可行。

procedure TCurrentObject.AVirtualMethod;
begin
  asm
        MOV     EDX,VMTOFFSET AVirtualMethod // 虚拟方法VMT偏移量
        MOV     EAX,Self                     // 对象实例 => EAX
        MOV     ECX,[EAX]                    // 类VMT => ECX
        MOV     ECX,[ECX].vmtParent
        MOV     ECX,[ECX]                    // 父类VMT => ECX
        MOV     ECX,[ECX].vmtParent
        MOV     ECX,[ECX]                    // 祖父类VMT => ECX
        MOV     ECX,[ECX+EDX]                // 祖父类虚拟方法地址 => ECX
        CALL    ECX                          // 方法调用
  end;
end;
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type
  TMyClassA=class(TStringList)
  public
    procedure KKK(); virtual;
  end;
  TMyClassB=class(TMyClassA)
  public
    procedure KKK();override;
  end;
  TMyClassC=class(TMyClassB)
  public
    procedure KKK(); override;
  end;
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
    A:TMyClassA;
    B:TMyClassB;
    C:TMyClassC;
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyClassA.KKK();
begin
  ShowMessage('TMyClassA.KKK');
end;
procedure TMyClassB.KKK();
begin
  inherited;
  ShowMessage('TMyClassB.KKK');
end;
procedure TMyClassC.KKK();
begin
  //inherited; 注释后  不就不执行 TMyClassB.KKK()
 // TMyClassA(self).KKK;    //虚方法时会异常,循环调用,
  asm
        MOV     EDX,VMTOFFSET KKK // 虚拟方法VMT偏移量
        MOV     EAX,Self                     // 对象实例 => EAX
        MOV     ECX,[EAX]                    // 类VMT => ECX
        MOV     ECX,[ECX].vmtParent
        MOV     ECX,[ECX]                    // 父类VMT => ECX
        MOV     ECX,[ECX].vmtParent
        MOV     ECX,[ECX]                    // 祖父类VMT => ECX
        MOV     ECX,[ECX+EDX]                // 祖父类虚拟方法地址 => ECX
        CALL    ECX                          // 方法调用
  end;
  ShowMessage('TMyClassC.KKK');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
    A:=TMyClassA.Create ;
    B:=TMyClassB.Create;
    C:=TMyClassC.Create;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  A.KKK;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  B.KKK;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
  C.KKK;
end;
end.
View Code

 

posted @ 2016-10-28 15:03  海蓝7  阅读(1405)  评论(0编辑  收藏  举报