日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

构造函数 Create 与 析构函数 Destroy

發布時間:2025/3/21 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 构造函数 Create 与 析构函数 Destroy 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考了萬一的博客:

http://www.cnblogs.com/del/archive/2007/12/13/993757.html

http://www.cnblogs.com/del/archive/2008/01/17/1042904.html

=====================================================================================

?

unit Unit5;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;typeTForm5 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;/// <summary>/// 定義一個 人類/// </summary>TPerson = class(TObject)privateFname: string;Fage: Integer;procedure Setage(const Value: Integer);procedure Setname(const Value: string);public/// <summary>/// 1由于 TObject類的構造方法 不是 虛方法 和 動態方法, 所以不能 overide/// 所以重定義一個Create/// 標準寫法1/// </summary>constructor Create;//overload; 若有多個重載,這里不要忘記加 overload/// <summary>/// 重載構造方法, 標準寫法2/// </summary>//constructor Create(const aName: string; const aAge: Integer); overload;/// <summary>/// 1.重寫即overide析構方法,由于tobject的析構方法是個虛方法,但是比較特殊,/// 子類可以選擇是否重寫(普通方法是不可以選擇的)////// 2.這樣寫是重定義,雖然允許這樣玩,但是你要知道父類是個虛方法,盡量不要這樣寫/// </summary>//destructor Destroy;/// <summary>/// 標準寫法, 重寫覆蓋父類的虛方法, 加上override 關鍵詞/// </summary>destructor Destroy; override;/// <summary>/// 重載析構方法, 不要這樣玩, 因為你要知道, 我們通常釋放對象都是用 MyObj.Free;來/// 調用Destroy的,而Free是沒有參數的, 所以若你這么玩, 那么你必須釋放的時候這樣寫/// MyObj.Destroy('a123') 且為了安全你還得與Free一致,方法體內釋放前判斷下對象是否為nil/// 不如直接用Free來的簡單,所以這種方法可以不用./// </summary>//destructor Destroy(a: string); overload;property name: string read Fname write Setname;property age: Integer read Fage write Setage;end;/// <summary>/// 定義一個人類的子類 婦女類/// </summary>TWoman = class(TPerson)public/// <summary>/// 重定義一個構造方法,測試默認不寫inherited Create的時候,是否調用了父類的構造方法/// 試驗證明: inherited Create 不可省略, 不寫的時候不調用父類的構造函數,這樣才是最/// 合理的。/// </summary>constructor Create;function makeLove(): string;end;varForm5: TForm5;implementation{$R *.dfm}{ TPerson }constructor TPerson.Create; begin//標準寫法inherited Create; end;//constructor TPerson.Create(const aName: string; const aAge: Integer); //begin // inherited Create; // Fname := aName; // Fage := aAge; //end;//destructor TPerson.Destroy(a: string); //begin // //end;destructor TPerson.Destroy; beginend;procedure TPerson.Setage(const Value: Integer); beginFage := Value; end;procedure TPerson.Setname(const Value: string); beginFname := Value; end;procedure TForm5.Button1Click(Sender: TObject); varpp: TPerson;mm: TWoman; beginpp := TPerson.Create;mm := TWoman.Create;tryfinallypp.Free;mm.Free;end;end;{ TWoman }constructor TWoman.Create; begin//不寫這句不調用父類的構造函數,所以還是寫上標準 安全。inherited Create; end;function TWoman.makeLove: string; beginend;end.

?

從哲學的角度講創建一個類的實例是這樣的;

創建走正序:父親.Create ----->> 兒子.Create ----->> 孫子.Create

銷毀走逆序:父親.Destroy?<<----- 兒子.Destroy <<----- 孫子.Destroy

即先有父親,父親把一些基本通用的成員屬性或方法初始化后 才能讓兒子繼承啊;沒有父親何來兒子呢;

所以一般不要把構造函數Create弄成虛函數。這樣做也沒意義;構造函數 一個類 重定義一個構造函數,子類的構造函數中可以使用inherit

來調用父類的構造函數,一般構造函數不會定義成虛函數,即不允許 overide ;比如 TObject的構造函數。

析構函數一般都是弄成虛函數,要求子類必須overide(雖然不overide也不報錯,但是你要養成良好的習慣,盡量這么做),這樣才能保證多態的

使用場景下,調用的是子類的析構函數,即:父類的實例 := 子類的.Create ;父類的實例.Free 依然是調用的

子類.Destroy 確保了;先銷毀子類的成員,再銷毀父類的成員。

?

unit Unit5;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;typeTForm5 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);procedure FormCreate(Sender: TObject);private{ Private declarations }public{ Public declarations }end;/// <summary>/// 父親類/// </summary>TFather = classprivateFname: string;Flist1: TStringList;procedure Setname(const Value: string);procedure Setlist1(const Value: TStringList);public//若需要初始化的時候做一些特殊的事的話,那么重定義構造函數constructor Create;//若需要銷毀的時候做一些特殊事的話,由于祖先類是虛函數,那么父類子類都需要overide到底.destructor Destroy; override;property name: string read Fname write Setname;property list1: TStringList read Flist1 write Setlist1;end;/// <summary>/// 兒子類/// </summary>TSon = class(TFather)privateFage: Integer;Flist2: TStringList;procedure Setage(const Value: Integer);procedure Setlist2(const Value: TStringList);public//若需要初始化的時候做一些特殊的事的話,那么重定義構造函數constructor Create;//若需要銷毀的時候做一些特殊事的話,由于祖先類是虛函數,那么父類子類都需要overide到底.destructor Destroy; override;property age: Integer read Fage write Setage;property list2: TStringList read Flist2 write Setlist2;end;/// <summary>/// 孫子類/// </summary>TGrandson = class(TSon)privateFsex: Boolean;procedure Setsex(const Value: Boolean);public//若需要初始化的時候做一些特殊的事的話,那么重定義構造函數constructor Create;//沒必要了,因為銷毀的時候不需要做事//destructor Destroy; override;property sex: Boolean read Fsex write Setsex;//如果不需要銷毀的時候做一些事,比如這里我不定義一個TStringList,那么就沒有必要去重寫父類的Destroy//property list3: TStringList read Flist3 write Setlist3;end;varForm5: TForm5;implementation{$R *.dfm}procedure TForm5.Button1Click(Sender: TObject); varsz: TGrandson; beginsz := TGrandson.Create;tryShowMessage(sz.name);ShowMessage(sz.list1.Text);finallysz.Free;end; end;{ TFather }constructor TFather.Create; begininherited Create;Self.Fname := '小李飛刀';Self.Flist1 := TStringList.Create;Self.Flist1.Add('111');OutputDebugString('父親'); end;{ TSon }constructor TSon.Create; begininherited Create;Self.Fage := 100;Self.Flist2 := TStringList.Create;Self.Flist2.Add('222');OutputDebugString('兒子'); end;{ TGrandson }constructor TGrandson.Create; begininherited Create;Self.sex := True;OutputDebugString('孫子'); end;destructor TFather.Destroy; beginSelf.Flist1.Free;inherited; end;procedure TFather.Setlist1(const Value: TStringList); beginFlist1 := Value; end;procedure TFather.Setname(const Value: string); beginFname := Value; end;destructor TSon.Destroy; beginSelf.Flist2.Free;inherited; end;procedure TSon.Setage(const Value: Integer); beginFage := Value; end;procedure TSon.Setlist2(const Value: TStringList); beginFlist2 := Value; end;procedure TGrandson.Setsex(const Value: Boolean); beginFsex := Value; end;procedure TForm5.FormCreate(Sender: TObject); beginReportMemoryLeaksOnShutdown := True; end;end.

?

?

創建孫子類的實例的時候,會逐級先向上一直追溯到TObject.Create,先把繼承過來的逐漸初始化一遍,才能輪到自己的。

?

?以下是網上的摘抄,不一定正確,切圖:

?

?

我覺得這個人 說的非常好,還是要看基類的,即祖先類。若祖先類 用了 virtual 那么無論是 構造函數 還是 析構函數,若你需要在構造和析構的時候 做一些特殊的事的話,那么你必須overide ,子類繼續overide,overide到底。養成良好的編程習慣。

?

接下來我來舉個例子來說明為什么,析構函數要能弄成虛方法:

例子1,重定義Destroy然后用Free來釋放的話,那么會內存泄露;

?

?

針對這個問題,當然有多重解決方案,比如重定義Free方法,或者釋放的時候用實例.Destroy ,然后為了安全 大不了 Destroy里 也判斷下 Self是否為nil; 但是這些解決方案都是把問題 復雜化的方案了。何必不用overide呢。把父類的Destroy給覆蓋掉。不就好了。即使再父類調用Free;由于 是子類創建的實例,那么父類的Destroy也是被子類的覆蓋掉了的,那么就能保證TObject.Free;實際上是調用了T人類.Destroy,這樣就不會有內存泄露了,這塊設計的復雜吧,一般人不深入研究根本不會明白,因為析構的時候,我們并沒有純純的使用Destroy,而是為了安全使用了Free; 而Free又是定義再父類的。

?

unit Unit5;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;typeTForm5 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);procedure FormCreate(Sender: TObject);private{ Private declarations }public{ Public declarations }end;/// <summary>/// 人類/// </summary>TPerson = classprivateFlist1: TStringList;procedure Setlist1(const Value: TStringList);publicconstructor Create;//這里Destroy我選擇了重定義,沒有覆蓋父類TObject.Destroy//當調用.Free來釋放的時候將永遠不會執行這個析構函數destructor Destroy;property list1: TStringList read Flist1 write Setlist1;end;varForm5: TForm5;implementation{$R *.dfm}{ TPerson }constructor TPerson.Create; begininherited;Self.Flist1 := TStringList.Create;Self.Flist1.Add('111'); end;destructor TPerson.Destroy; beginSelf.Flist1.Free;inherited; end;procedure TPerson.Setlist1(const Value: TStringList); beginSelf.Flist1 := Value; end;procedure TForm5.Button1Click(Sender: TObject); varpp: TPerson; beginpp := TPerson.Create;tryShowMessage(pp.list1.Text);finally//這里根本就沒有調用我們上面聲明的Destroy,依然是調用父類的Destroy,//因為Free是Free是個普通的方法聲明父類,所以他依然是調用了父類的Destroy什么都沒有做//所以這里就會有內存泄露 pp.Free;end; end;procedure TForm5.FormCreate(Sender: TObject); beginReportMemoryLeaksOnShutdown := True; end;end.

?

?

?

?

?

?

這篇博客可以說是百忙之中寫出來的,由于這塊設計的邏輯 會有點繞;我來個結論吧:

1.構造方法,如果子類需要加強,或需要重載,那么就需要重定義;

2.析構方法,如果子類需要加強,那么就需要重寫覆蓋overide父類的,且析構方法一般不重載。

3.普通方法,如果子類需要加強,那么就需要父類定義成虛方法,然后子類覆蓋overide;只有這樣才能做到多態的情況下使用。

?

?

?

2017-05-23 補充:

對于繼承組件的類 構造方法必須覆蓋;

?

?

?

?

轉載于:https://www.cnblogs.com/del88/archive/2012/01/18/2325722.html

總結

以上是生活随笔為你收集整理的构造函数 Create 与 析构函数 Destroy的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。