首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于TObject类型调用虚拟构造函数

基于TObject类型调用虚拟构造函数
EN

Stack Overflow用户
提问于 2020-09-11 20:16:24
回答 2查看 265关注 0票数 1

我有一个从TStringList对象派生出来的对象,我称之为“TAutoString”。它允许您在创建列表时指定对象类型。然后,每次将一个新条目添加到字符串列表中时,它还会创建与该字符串条目关联的对象的副本。这使得存储与每个字符串一起的各种附加信息变得很容易。例如:

代码语言:javascript
复制
type TMyObject = class(TObject)
 public
  Cats: integer;
  Dogs: integer;
  Mice: integer;
 end;

MO := TAutoString.Create(TMyObject);

在对象内部,类信息存储在一个类变量中:

代码语言:javascript
复制
 private
  ObjectClass: TClass;


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

现在,每次添加新项时,它都会创建指定类型的新对象:

代码语言:javascript
复制
function TAutoString.Add(const S: string): Integer;
begin
    Result:=inherited Add(S);
    Objects[Result]:=ObjectClass.Create;
end;

我现在可以添加或读取与每个字符串条目相关的信息。

代码语言:javascript
复制
   TMyObject(MO.Objects[25]).Cats := 17;
   D:=TMyObject(MO.Objects[25]).Dogs;

这很好,因为对象没有构造函数。如果对象有构造函数,则在创建对象时不会调用它的构造函数,因为TObject的构造函数不是虚拟的。

有人能想出解决这个问题的办法吗。我见过使用RTTI库的解决方案,但这是在Delphi-7中,它没有RTTI库。

顺便说一句,TObject的构造函数不是虚拟的,这似乎有点奇怪。如果是的话,它将启用各种有用的特性,比如我正在尝试实现的特性。

编辑:雷米下面的建议只是我需要的提示。我最初尝试过一种类似的策略,但我无法让它发挥作用。当它看起来不像我想的那样工作的时候,我想一定有一些关于虚拟方法我不理解的东西。他的帖子迫使我再看一遍。结果是,我没有对要附加的对象的构造函数执行“覆盖”指令。现在它的工作方式正是它应该做的。

我关心的另一个问题是,我已经在许多其他应用程序中使用了Auto,在这些应用程序中,对象是基于"TObject“的,我不想回去修改所有这些代码。我通过重载构造函数并拥有一个用于基于TObject的对象和另一个用于我的TAutoClass对象来解决这个问题:

代码语言:javascript
复制
  constructor Create(ObjClass: TAutoClass); overload; virtual;
  constructor Create(ObjClass: TClass); overload; virtual;

根据调用构造函数的不同,存储在不同变量中的对象类。

代码语言:javascript
复制
 private
  AutoClass: TAutoClass;
  ObjectClass: TClass;

然后,在构造对象时,我检查分配了哪些对象,并使用该对象:

代码语言:javascript
复制
procedure TAutoString.CreateClassInstance(Index: integer);
begin
   if AutoClass<>nil then Objects[Index]:=AutoClass.Create
   else Objects[Index]:=ObjectClass.Create
end;

新版本完美地适用于两种类型的对象。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-11 20:54:08

要做您想做的事情,您必须为要派生的list对象定义一个基类,然后可以向该类添加一个虚拟构造函数。您的ObjectClass成员必须使用该类类型,而不是使用TClass

例如:

代码语言:javascript
复制
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,例如:

代码语言:javascript
复制
type
  TMyObject = class(TAutoStringObject)
  public
    ...
    constructor Create; override;
  end;

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

并且它们的构造函数将如预期的那样被调用。

票数 3
EN

Stack Overflow用户

发布于 2021-10-23 10:26:26

下面是一个更干净的解决方案的提示:

可以向Tobject添加虚拟构造函数。

要做到这一点,您需要使用所谓的“类助手”。

下面是一个示例:

代码语言:javascript
复制
type
    TobjectHelper = class helper for Tobject
    public
        constructor Create; virtual; // adds a virtual constructor to Tobject.
    end;

(我的用例是一个TryCreateObject函数,用于检测对象创建过程中内存不足的情况,包装try除了结束,只返回true/false以防止代码中的try以外块,而是使用更多可控制的逻辑if语句)

班级助教人数最多(?)在Delphi 8及更高版本中介绍的。您的要求是德尔菲7,所以这可能不起作用。

除非您为Windows 95/Windows 98/Windows XP编写代码,否则可能是时候升级到最新版本的Delphi,特别是用于unicode支持的Delphi XE版本,否则您将针对即将过时的老化平台进行编码。

然而,对于Windows 95/Windows 98和Windows,我确实认为Delphi 2007可能有一些用处,我相信它可以编译可以在那些旧的windows平台上运行的代码,但我可能错了。

Delphi的后期版本需要有特定的windows系统dlls,否则构建/编译的可执行文件将无法运行,w95/w98/wxp缺少这些dll。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63853776

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档