继承,重载,覆盖的问题! (100分)

  • 主题发起人 主题发起人 demon_yx
  • 开始时间 开始时间
D

demon_yx

Unregistered / Unconfirmed
GUEST, unregistred user!
type
Tperson=class
public
procedure draw();virtual;
end;

Tman=class(Tperson)
public
procedure draw();overload;
end;

Twoman=class(Tperson)
public
procedure draw();override;
end;

Tform=class(Tform)
public
a:Tman;
b:Twoman;
end;

procedure Tperson.draw();
begin
showmessage('person');
end;

procedure Twoman.draw();
begin
showmessage('woman');
end;
procedure Tman.draw();
begin
showmessage('man');
end;

procedure TForm1.Button2Click(Sender: TObject);
//var
// b:Twoman;
begin
// b:=Twoman.creat;
a.draw <---正确!
b.draw 〈---错误!

end

这样用覆盖是错误的,为什么?
 
搞错了!
procedure TForm1.Button2Click(Sender: TObject);
var
b:Twoman
<----这里声明不会错,(在button2.click时)
begin
b:=Twoman.creat;
b.draw
end


但我这样声明时:
TForm1 = class(TForm)
public
b:Twoman
<---在这里声明是错的!(在button2.click时)
end;
 
>> 这样用覆盖是错误的,为什么?
什么意思?

这样不是很好吗? 只是下次你要记得 加上 : B.Free;
 
procedure Twoman.draw();
begin
showmessage('woman');
end;
这里应该是这样!
 
>> <---在这里声明是错的!(在button2.click时)

有什么错呀?
 
unit overloadandoverride;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
Tperson=class
public
procedure draw();virtual;
end;

Tman=class(Tperson)
public
procedure draw();overload;
end;

Twoman=class(Tperson)
public
procedure draw();override;
end;

TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private

{ Private declarations }
public
a:Tman;
b:Twoman
<-----注意这里!
{ Public declarations }
end;
var
Form1: TForm1;

implementation
{$R *.DFM}

procedure Tperson.draw();
begin
showmessage('person');
end;
procedure Tman.draw();
begin
showmessage('man');
end;
procedure Twoman.draw();
begin
showmessage('woman');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
a.draw
end;

procedure TForm1.Button2Click(Sender: TObject);
//var
// b:Twoman
<-----注意这里!(这里声明是对的)
begin
// b:=Twoman.create
b.draw
end;

end.

你拷过去运行一下吧!
 
procedure TForm1.Button2Click(Sender: TObject);
var
b:Twoman
<----这里声明不会错,(在button2.click时)
begin
b:=Twoman.creat;
b.draw
end


如果为全局变量,要记得释放。不能多次创建而不释放。
 
我试了你的程序,下面是我写的全部代码,运行没有问题:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
Tperson=class
public
procedure draw();virtual;
end;

Twoman=class(Tperson)
public
procedure draw();override;
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
b:Twoman;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

{ Tperson }

procedure Tperson.draw;
begin
showmessage('person');
end;

{ Twoman }

procedure Twoman.draw;
begin
showmessage('woman');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
b:=Twoman.create;
b.draw;
b.free;
end;

end.
 
现在问题出现了
procedure TForm1.Button1Click(Sender: TObject);
begin
b:=Twoman.create;
b.draw;
b.free;
end;
为什么overload时,a:=Tman.create 这一句不需要!
而override时,b:=Twoman.create这一句一定要!
我的源码里体现了这一点!
 
下面的程序运行后也没有任何问题,我估计你是因为没有创建a和b这两个类型,
所以会报“模块访问冲突”的错误,明显就是地址错误,赵下面这样写就行了。

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
Tperson=class
public
procedure draw();virtual;
end;

Tman=class(Tperson)
public
procedure draw();overload;
end;

Twoman=class(Tperson)
public
procedure draw();override;
end;

TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
a:Tman;
b:Twoman;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

{ Tperson }

procedure Tperson.draw;
begin
showmessage('person');
end;

{ Tman }

procedure Tman.draw;
begin
showmessage('man');
end;

{ Twoman }

procedure Twoman.draw;
begin
showmessage('woman');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
a:=Tman.create
//------创建变量a
a.draw;
a.free
//------释放a
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
b:=Twoman.create
//------创建变量b
b.draw;
b.free
//------释放b
end;

end.
 
to:westboy2000
a:=Tman.create
//------创建变量a
这一句不要是可以的!
b:=Twoman.create
//------创建变量b
这一句不要是不可以的,
为什么?

 
具体原因我也不清楚,不过我发现如果将函数中的virtual、overload、override都去掉,
引用时即使不create也不会报错。但是只限于showmessage()这类的事件,因为他们不访问
内存,如果在每个类里面加上一些其他属性,只要一访问就会报错,看来,对于不访问内存
的变量,不需要创建就可以直接使用,当然,这纯属我的猜测,也许有别的原因?
不过我还是强烈建议先创建、再调用、最后释放的写法,最规则、最标准、容易读、不出错。[:)]
 
TMan.Draw 是静态方法,所以方法的代码入口在链接时已经确定下来。你没有调用 TMan.Create
而能够正确地调用 TMan.Draw 是因为 TMan.Draw 中没有访问对象实例的任何字段或属性,若
若你改一下:
TMan=class(TPerson)
FMan: Integer;
procedure draw();overload;
end;
...
procedure TMan.Draw;
begin
FMan := 1
//加上这句
showmessage('man');
end;
则不先调用 TMan.Create 创建对象实例就执行 TMan.Draw 将出内存访问错,因为实例的内
存空间尚未分配和初始化。
而 TWoman.Draw override 了 TPerson.Draw 这个虚拟方法,所以 TWonman.Draw 也是虚拟
方法,对该方法的调用,其代码入口是运行时才能决定的,即动态绑定,这是通过运行时在
对象的虚拟方法表(VMT)中搜索方法的入口来实现的,而创建对象时会为其分配内存,初始化
字段,在对象中设置一个指向 VMT 的指针等,你没有调用 TWoman.Create 就执行
TWoman.Draw ,因对象实例还未建立,无法正确根据对象中的 VMT 指针在 VMT 中查找 Draw
方法的代码入口,就产生了错误。因此要先创建对象,才能访问其数据和方法。

 
多谢bbkxjy,高手啊,这下明白了。[:)]
 
多谢bbkxjy
 
多人接受答案了。
 
后退
顶部