简体   繁体   English

Delphi根据TObject类型调用虚构造函数

[英]Delphi calling a virtual constructor based on the TObject type

I have an object that is derived from the TStringList object that I call a "TAutoString."我有一个派生自 TStringList 对象的对象,我称之为“TAutoString”。 It allows you to specify an object type when the list is created.它允许您在创建列表时指定对象类型 Then each time a new entry is added to the string list, it also creates a copy of the object associated with that string entry.然后每次将新条目添加到字符串列表时,它还会创建与该字符串条目关联的对象的副本。 This makes it easy to store all kinds of additional information along with each string.这使得在每个字符串中存储各种附加信息变得容易。 For example:例如:

type TMyObject = class(TObject)
 public
  Cats: integer;
  Dogs: integer;
  Mice: integer;
 end;

MO := TAutoString.Create(TMyObject);

Inside the object, the class information is stored in a class variable:在对象内部,类信息存储在类变量中:

 private
  ObjectClass: TClass;


constructor TAutoString.Create(ObjClass: TClass);
begin
    inherited Create;
    ObjectClass:=ObjClass;
end;

Now, every time a new item is added, it creates a new object of the specified type:现在,每次添加新项目时,它都会创建一个指定类型的新对象:

function TAutoString.Add(const S: string): Integer;
begin
    Result:=inherited Add(S);
    Objects[Result]:=ObjectClass.Create;
end;

I can now add or read information associated with each string entry.我现在可以添加或读取与每个字符串条目相关的信息。

   TMyObject(MO.Objects[25]).Cats := 17;
   D:=TMyObject(MO.Objects[25]).Dogs;

This works great as along as the object doesn't have a constructor.这很有效,因为对象没有构造函数。 If the object has a constructor, its constructor won't get called when the object is created because the constructor for TObject is not virtual.如果对象具有构造函数,则在创建对象时不会调用其构造函数,因为 TObject 的构造函数不是虚拟的。

Can anyone think of a way around this problem.任何人都可以想出解决这个问题的方法。 I've seen solutions that use the RTTI libraries, but this is in Delphi-7, which doesn't have an RTTI library.我见过使用 RTTI 库的解决方案,但这是在 Delphi-7 中,它没有 RTTI 库。

As an aside, it seems a bit strange that TObject's constructor is not virtual.顺便说一句,TObject 的构造函数不是虚拟的,这似乎有点奇怪。 If it were, it would enable all sorts of useful features like the one I'm trying to implement.如果是这样,它将启用各种有用的功能,例如我正在尝试实现的功能。

EDIT: Remy's suggestion below was just the nudge I needed.编辑:下面雷米的建议只是我需要的推动。 I had originally tried a similar strategy, but I couldn't make it work.我最初尝试过类似的策略,但我无法让它发挥作用。 When it didn't seem to work the way I thought it should, I assumed there must be something that I didn't understand about virtual methods.当它似乎没有按照我认为应该的方式工作时,我认为一定有一些我不了解虚拟方法的地方。 His post pushed me to look at it again.他的帖子让我又看了一遍。 It turned out that I had left off the "Override" directive for the constructor of the object I wanted to attach.原来我已经放弃了我想要附加的对象的构造函数的“覆盖”指令。 Now it works just the way it should.现在它按照它应该的方式工作。

The other issue I was concerned about was that I had already used the Auto Strings in a bunch of other applications where the object was based on "TObject" and I didn't want to go back and change all that code.我担心的另一个问题是我已经在一堆其他应用程序中使用了自动字符串,其中对象基于“TObject”,我不想回去更改所有代码。 I solved that issue by overloading the constructors and having one for TObject-based objects and another my TAutoClass objects:我通过重载构造函数并让一个用于基于 TObject 的对象和另一个用于我的 TAutoClass 对象来解决这个问题:

  constructor Create(ObjClass: TAutoClass); overload; virtual;
  constructor Create(ObjClass: TClass); overload; virtual;

Depending on which constructor is called, the object class stored in a different in a different variable.根据调用的构造函数不同,对象类存储在不同的变量中。

 private
  AutoClass: TAutoClass;
  ObjectClass: TClass;

Then when the object is constructed I check to see which has been assigned and use that one:然后在构造对象时,我检查已分配的对象并使用该对象:

procedure TAutoString.CreateClassInstance(Index: integer);
begin
   if AutoClass<>nil then Objects[Index]:=AutoClass.Create
   else Objects[Index]:=ObjectClass.Create
end;

The new version works perfectly with either type of object.新版本适用于任何一种类型的对象。

To do what you want, you will have to define a base class for your list objects to derive from, and then you can add a virtual constructor to that class.要执行您想要的操作,您必须为要派生的列表对象定义一个基类,然后您可以向该类添加一个虚拟构造函数。 Your ObjectClass member will have to use that class type instead of using TClass .您的ObjectClass成员将不得不使用该类类型而不是使用TClass

For example:例如:

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;

...

Then, you simply adjust your derived object classes to use TAutoStringObject instead of TObject , eg:然后,您只需调整您的派生对象类以使用TAutoStringObject而不是TObject ,例如:

type
  TMyObject = class(TAutoStringObject)
  public
    ...
    constructor Create; override;
  end;

MO := TAutoString.Create(TMyObject);
...

And their constructor will be called, as expected.并且它们的构造函数将按预期被调用。

Here is a hint for a cleaner solution:这是一个更清洁的解决方案的提示:

It is possible to add a virtual constructor to Tobject.可以向 Tobject 添加虚拟构造函数。

To do so you will need to use what is called a "class helper".为此,您需要使用所谓的“类助手”。

Here is an example:下面是一个例子:

type
    TobjectHelper = class helper for Tobject
    public
        constructor Create; virtual; // adds a virtual constructor to Tobject.
    end;

(My use case was a TryCreateObject function to detect out of memory situation during object creation, wraps try except end and simply returns true/false to prevent try except blocks in code and instead use more logic controleable if statements) (我的用例是一个 TryCreateObject 函数,用于在对象创建期间检测内存不足的情况,包装 try except end 并简单地返回 true/false 以防止代码中的 try except 块,而是使用更多逻辑可控的 if 语句)

Class helpers were apperently(?) introduced in Delphi 8 and later.类助手是在 Delphi 8 及更高版本中明显(?)引入的。 Your requirements is for Delphi 7 so this may not work.您的要求适用于 Delphi 7,因此这可能不起作用。

Unless you coding for Windows 95/Windows 98/Windows XP it may be time for you to upgrade to a more recent version of Delphi, especially the Delphi XE versions for unicode support, otherwise you coding against an aging platform that is about to become obsolete etc.除非您为 Windows 95/Windows 98/Windows XP 编码,否则您可能需要升级到更新版本的 Delphi,尤其是支持 unicode 的 Delphi XE 版本,否则您将针对即将过时的老化平台进行编码等等。

However for Windows 95/Windows 98 and Windows XP I do believe Delphi 2007 may be of some use, I believe it can compile code that can run on those older windows platforms, I could be wrong though.但是对于 Windows 95/Windows 98 和 Windows XP,我确实相信 Delphi 2007 可能会有用,我相信它可以编译可以在那些较旧的 Windows 平台上运行的代码,不过我可能是错的。

Later versions of Delphi require certain windows system DLLs to be present otherwise the build/compiled executable will not run, w95/w98/wxp lack these dlls. Delphi 的更高版本要求存在某些 Windows 系统 DLL,否则构建/编译的可执行文件将无法运行,w95/w98/wxp 缺少这些 DLL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM