一般继承 /虚方法 跳过父类执行 祖父类的方法
背景:某一天不小心把基类函数写成了 虚函数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.