[英]Delphi calling a virtual constructor based on the TObject type
我有一個派生自 TStringList 對象的對象,我稱之為“TAutoString”。 它允許您在創建列表時指定對象類型。 然后每次將新條目添加到字符串列表時,它還會創建與該字符串條目關聯的對象的副本。 這使得在每個字符串中存儲各種附加信息變得容易。 例如:
type TMyObject = class(TObject)
public
Cats: integer;
Dogs: integer;
Mice: integer;
end;
MO := TAutoString.Create(TMyObject);
在對象內部,類信息存儲在類變量中:
private
ObjectClass: TClass;
constructor TAutoString.Create(ObjClass: TClass);
begin
inherited Create;
ObjectClass:=ObjClass;
end;
現在,每次添加新項目時,它都會創建一個指定類型的新對象:
function TAutoString.Add(const S: string): Integer;
begin
Result:=inherited Add(S);
Objects[Result]:=ObjectClass.Create;
end;
我現在可以添加或讀取與每個字符串條目相關的信息。
TMyObject(MO.Objects[25]).Cats := 17;
D:=TMyObject(MO.Objects[25]).Dogs;
這很有效,因為對象沒有構造函數。 如果對象具有構造函數,則在創建對象時不會調用其構造函數,因為 TObject 的構造函數不是虛擬的。
任何人都可以想出解決這個問題的方法。 我見過使用 RTTI 庫的解決方案,但這是在 Delphi-7 中,它沒有 RTTI 庫。
順便說一句,TObject 的構造函數不是虛擬的,這似乎有點奇怪。 如果是這樣,它將啟用各種有用的功能,例如我正在嘗試實現的功能。
編輯:下面雷米的建議只是我需要的推動。 我最初嘗試過類似的策略,但我無法讓它發揮作用。 當它似乎沒有按照我認為應該的方式工作時,我認為一定有一些我不了解虛擬方法的地方。 他的帖子讓我又看了一遍。 原來我已經放棄了我想要附加的對象的構造函數的“覆蓋”指令。 現在它按照它應該的方式工作。
我擔心的另一個問題是我已經在一堆其他應用程序中使用了自動字符串,其中對象基於“TObject”,我不想回去更改所有代碼。 我通過重載構造函數並讓一個用於基於 TObject 的對象和另一個用於我的 TAutoClass 對象來解決這個問題:
constructor Create(ObjClass: TAutoClass); overload; virtual;
constructor Create(ObjClass: TClass); overload; virtual;
根據調用的構造函數不同,對象類存儲在不同的變量中。
private
AutoClass: TAutoClass;
ObjectClass: TClass;
然后在構造對象時,我檢查已分配的對象並使用該對象:
procedure TAutoString.CreateClassInstance(Index: integer);
begin
if AutoClass<>nil then Objects[Index]:=AutoClass.Create
else Objects[Index]:=ObjectClass.Create
end;
新版本適用於任何一種類型的對象。
要執行您想要的操作,您必須為要派生的列表對象定義一個基類,然后您可以向該類添加一個虛擬構造函數。 您的ObjectClass
成員將不得不使用該類類型而不是使用TClass
。
例如:
type
TAutoStringObject = class(TObject)
public
constructor Create; virtual;
end;
TAutoStringObjectClass = class of TAutoStringObject;
TAutoString = class(TStringList)
private
ObjectClass: TAutoStringObjectClass;
public
constructor Create(ObjClass: TAutoStringObjectClass);
function Add(const S: string): Integer; override;
...
end;
...
constructor TAutoStringObject.Create;
begin
inherited Create;
end;
constructor TAutoString.Create(ObjClass: TAutoStringObjectClass);
begin
inherited Create;
ObjectClass := ObjClass;
end;
function TAutoString.Add(const S: string): Integer;
var
Obj: TAutoStringObject;
begin
Obj := ObjectClass.Create;
try
Result := inherited AddObject(S, Obj);
except
Obj.Free;
raise;
end;
end;
...
然后,您只需調整您的派生對象類以使用TAutoStringObject
而不是TObject
,例如:
type
TMyObject = class(TAutoStringObject)
public
...
constructor Create; override;
end;
MO := TAutoString.Create(TMyObject);
...
並且它們的構造函數將按預期被調用。
這是一個更清潔的解決方案的提示:
可以向 Tobject 添加虛擬構造函數。
為此,您需要使用所謂的“類助手”。
下面是一個例子:
type
TobjectHelper = class helper for Tobject
public
constructor Create; virtual; // adds a virtual constructor to Tobject.
end;
(我的用例是一個 TryCreateObject 函數,用於在對象創建期間檢測內存不足的情況,包裝 try except end 並簡單地返回 true/false 以防止代碼中的 try except 塊,而是使用更多邏輯可控的 if 語句)
類助手是在 Delphi 8 及更高版本中明顯(?)引入的。 您的要求適用於 Delphi 7,因此這可能不起作用。
除非您為 Windows 95/Windows 98/Windows XP 編碼,否則您可能需要升級到更新版本的 Delphi,尤其是支持 unicode 的 Delphi XE 版本,否則您將針對即將過時的老化平台進行編碼等等。
但是對於 Windows 95/Windows 98 和 Windows XP,我確實相信 Delphi 2007 可能會有用,我相信它可以編譯可以在那些較舊的 Windows 平台上運行的代碼,不過我可能是錯的。
Delphi 的更高版本要求存在某些 Windows 系統 DLL,否則構建/編譯的可執行文件將無法運行,w95/w98/wxp 缺少這些 DLL。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.