首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

关于父类与子类的一点疑问、该如何处理

2012-03-19 
关于父类与子类的一点疑问、(昨天自己去翻译一个C#的代码、那个泛型着实把我膈应了一把、好不容易改写完、也碰

关于父类与子类的一点疑问、
(昨天自己去翻译一个C#的代码、那个泛型着实把我膈应了一把、好不容易改写完、也碰到一些小问题、我对于这些概念性的一直很模糊)

Delphi(Pascal) code
unit Unit1;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls;type  Aa = class(TObject)    public      constructor Create;      destructor Destroy;      function abc:Cardinal; //为了防止编译器优化掉循环  end;type  Bb = class(Aa)    public      ss:TStringList;//用户占用内存方便观察      constructor Create;      destructor Destroy;      procedure Free;  end;type  TForm1 = class(TForm)    btn1: TButton;    btn2: TButton;    btn3: TButton;    btn4: TButton;    btn5: TButton;    btn6: TButton;    btn7: TButton;    btn8: TButton;    procedure btn1Click(Sender: TObject);    procedure btn2Click(Sender: TObject);    procedure btn3Click(Sender: TObject);    procedure btn4Click(Sender: TObject);    procedure btn5Click(Sender: TObject);    procedure btn6Click(Sender: TObject);    procedure btn7Click(Sender: TObject);    procedure btn8Click(Sender: TObject);    procedure FormCreate(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;var  Form1: TForm1;implementation{$R *.dfm}{ Aa }function Aa.abc: Cardinal;begin  Result:=Random(9999);end;constructor Aa.Create;begin  inherited;end;destructor Aa.Destroy;begin  inherited;end;{ Bb }constructor Bb.Create;begin  inherited;  ss:=TStringList.Create;end;destructor Bb.Destroy;begin  ss.Free;  inherited;end;{如果自己写Free就需要这么写?procedure Bb.Free;begin  if Self <> nil then    Self.Destroy;  Self:=nil;end;}procedure TForm1.btn1Click(Sender: TObject);  //Create后不释放var  ii,rnd:Cardinal;  k:Aa;begin  for ii := 0 to 99999 do  begin    k:=Aa.Create;    rnd:=k.abc; //防止编译器把循环给优化掉  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  //通过观察内存使用量、大概每次占用1.7M内存没有释放end;procedure TForm1.btn2Click(Sender: TObject);var  ii,rnd:Cardinal;  k:Aa;begin  for ii := 0 to 99999 do  begin    k:=Aa.Create;    rnd:=k.abc;    k.Destroy;  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  //循环完毕、基本内存使用量无变化(几十K的变化、忽略)end;procedure TForm1.btn3Click(Sender: TObject);var  ii,rnd:Cardinal;  k:Aa;begin  for ii := 0 to 99999 do  begin    k:=Aa.Create;    rnd:=k.abc;    k.Free;  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  //循环完毕、基本内存使用量无变化(同调用Destroy方法)end;procedure TForm1.btn4Click(Sender: TObject);var  ii,rnd:Cardinal;  k:Aa;begin  for ii := 0 to 99999 do  begin    k:=Aa.Create;    rnd:=k.abc;    FreeAndNil(k);  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  //循环完毕、基本内存使用量无变化(同调用Destroy方法)end;//***********Bb类测试************************************procedure TForm1.btn5Click(Sender: TObject);var  ii,rnd:Cardinal;  k:Bb;begin  for ii := 0 to 99999 do  begin    k:=Bb.Create;    rnd:=k.abc; //防止编译器把循环给优化掉  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  //通过观察内存使用量、大概每次占用9M内存没有释放end;procedure TForm1.btn6Click(Sender: TObject);var  ii,rnd:Cardinal;  k:Bb;begin  for ii := 0 to 99999 do  begin    k:=Bb.Create;    rnd:=k.abc; //防止编译器把循环给优化掉    k.Destroy;  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  //通过观察内存使用量、使用量基本无变化end;procedure TForm1.btn7Click(Sender: TObject);var  ii,rnd:Cardinal;  k:Bb;begin  for ii := 0 to 99999 do  begin    k:=Bb.Create;    rnd:=k.abc; {防止编译器把循环给优化掉}    k.Free;  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  {通过观察内存使用量、每次有8M没有释放}end;procedure TForm1.btn8Click(Sender: TObject);var  ii,rnd:Cardinal;  k:Bb;begin  for ii := 0 to 99999 do  begin    k:=Bb.Create;    rnd:=k.abc; //防止编译器把循环给优化掉    FreeAndNil(k);  end;  ShowMessage(IntToStr(rnd) + #13 + '完成了');  //通过观察内存使用量、每次有8M没有释放end;procedure TForm1.FormCreate(Sender: TObject);var  k:Bb;begin  k:=Bb.Create;  ShowMessage(IntToStr(k.abc));  {  //第一种方法  k.Free;  //第二种方法  FreeAndNil(k);  //第三种方法  k.Destroy;  //第四种方法  //k.Destroy;  k:=nil;  }  ShowMessage(IntToStr(k.abc));  //无论选择四种中的哪一种、依旧可以返回一个数值、这又是为什么呢?end;end. 



Aa类和Bb差别只是在创建Bb类的时候、他创建了一个其他的对象实例、

因为Aa/Bb类都没有申明Free方法、那么就应该是调用了继承自TObject的Free方法、
那么当Aa的实例被创建后、其本身的数据结构占用了一定的内存、
如果调用了Free或者Destroy方法、则会把相应的内存给释放、
在Aa中测试、Free和Destroy方法效果几乎是一样的
然而在测试Bb类的时候、Free和Destroy就不一样了、从内存占用的数量来看、应该是Free只释放了自身、却并没有释放类中对象的实例、而FreeAndNil效果基本同Free

所以我有下面的想法、不知道是否正确:
1.我发现Free方法并不调用Destroy方法(我在Destroy里下断点、没断下来;当然可以自己写Free方法来调用Destroy)
2.FreeAndNil(Obj)等价于Obj.Free; Obj:=nil;
3.创建/销毁子类实例、并不会自动的调用父类的构造函数/析构函数、必须在子类的构造/析构函数里用inherited关键字去调用父类的函数、

如果上面第一条我说的是正确的话、那么要实现Free能够释放所有的内存就必须自己在类里面写个Free方法?像这样?

Delphi(Pascal) code
procedure Bb.Free;begin  if Self <> nil then    Self.Destroy;  Self:=nil;end;
 

另外还有一个问题、依旧是上面举例的两个类、存在以下代码:

Delphi(Pascal) code
var  k:Bb;begin  k:=Bb.Create;  ShowMessage(IntToStr(k.abc));  {  //第一种方法  k.Free;  //第二种方法  FreeAndNil(k);  //第三种方法  k.Destroy;  //第四种方法  //k.Destroy;  k:=nil;  }  ShowMessage(IntToStr(k.abc));  //无论选择四种中的哪一种、依旧可以返回一个数值、这又是为什么呢?


按理来说第二种和第四种方法、已经把变量变成了空指针、为何还能调用函数并获得返回值呢?
delphi中是不可能创建出对象的实例的(其实表述的不对、我想不起来正确应该怎么表示了)、例如:

var
  a:TStringList;

无论如何a都不可能是对象的、a永远是个指向对象的指针、这和C++的代码:
TStringList a;
是完全不同的、我觉得delphi里这样的代码应该是等同于C++中
TStringList *a;
那么既然我已经把变量设置成了空指针、上面的竟然还能返回一个值、我恨不能理解、求高手指教、

对于我上面的第三条、如果确实是这样的话、那么就不太理解构造析构函数名强制为Create/Destroy的意义、反正都需要用户显式的去调用(难到这就体现了delphi的严谨?)比如C++申明了一个对象的实例、那么在他生命周期结束时、会自动的调用析构函数、并且子类也会自动的调用父类的析构函数(会不会自动的调用父类的析构函数不确定、别人告诉我是可以的)、

[解决办法]
好长的内容,有点看不过来

热点排行