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

Posted 是蓝蓝的呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一般继承 /虚方法 跳过父类执行 祖父类的方法相关的知识,希望对你有一定的参考价值。

背景:某一天不小心把基类函数写成了 虚函数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

 

以上是关于一般继承 /虚方法 跳过父类执行 祖父类的方法的主要内容,如果未能解决你的问题,请参考以下文章

如果父类有一个虚方法,子类重写了这个方法。那么子类到底有没有继承父类的虚方法??

C++中,子类会继承父类的虚函数表!对于父类的析构函数(虚函数) 也会继承吗?

面向对象:继承抽象类抽象方法虚方法

java 继承父类 是会先执行父类吗

C++ 中,类的继承:父类当使用虚函数时候,子类对该函数进行重写的话,属于子类成员函数对虚函数的覆盖!

Delphi子类调用祖父类的虚函数