对象实例没有创建它

时间:2011-03-23 13:22:41

标签: delphi

我想知道是否有可能没有直接调用任何构造函数的对象实例。这样的事情:

var
  aObject : TMyObject;
begin
  aObject.MyMethod; //will cause an AV, but is it possible?
end;

编辑:

我知道静态方法,但那不是我想要的。我正在寻找一种方法来调用构造函数而无需显式调用它。

8 个答案:

答案 0 :(得分:12)

Delphi的对象都是堆分配的:你不能简单地声明一个对象并在其上调用方法,就像你在C ++中所做的那样,你必须调用一个构造函数来分配和设置内存。但请注意,即使在C ++中,实际上在调用构造函数时也是如此!

也许你可以逃脱记录而不是对象?例如:

type
  TMyObject = record // name intentionally left as in OP's code
    procedure MyMethod;
  end;

procedure TMyObject.MyMethod;
begin
  // Do something
end;

// Use example:
procedure Test;
var MyObject: TMyObject; // TMyObject is a record so it is stack-allocated
begin
  MyObject.MyMethod; // Works.
end;

答案 1 :(得分:9)

如你所知,这很奇怪。但是,只要该方法是静态的并且不引用Self,那么这将起作用。

当然,这样的事情被称为class method。也许这就是你想要的?

type
  TMyObject = class
    class procedure MyClassMethod;
  end;
...
TMyObject.MyClassMethod;

修改

您编辑了自己的问题。显然你知道所有关于静态方法的知识。您不希望在未初始化的对象上调用方法。

实际上,您现在声明您希望在未初始化的对象实例上调用方法的行为导致正在创建实例并调用该方法。

这是不可能的。任何为你调用构造函数的东西都没有魔力。

答案 2 :(得分:2)

您可以使用以下方式“分配”对象:

class function NewInstance: TObject; virtual;

此函数分配并初始化对象。之后,您可以将“create”构造函数作为它的正常函数调用(这是当您深入到程序集/ CPU视图时构造函数Create的工作方式)

答案 3 :(得分:2)

Delphi - 与C ++不同 - 没有自动创建构造函数的默认方法。

它与Delphi如何管理变量和范围有关。

在C ++中,当变量进入作用域时,它会自动调用构造函数。

你所追求的是RAII(资源获取是初始化)。

Barry Kelly(Delphi编译工程师之一)编写了interesting article about RAII in Delphi

他的解决方案基于Delphi中接口的自动重新计数。

解释这个基本上意味着复制/粘贴他的文章,所以请按照上面的链接阅读。

- 的Jeroen

答案 4 :(得分:1)

没有。实际上有几个问题:

  1. 你需要一些如何初始化变量。要么创建对象,要么创建NIL,以便该方法可以安全地检测是否已创建变量
  2. 如果(1)没有创建对象,方法invokation需要生成代码以查看对象是否已创建,并在必要时创建它。
  3. 然后就是破坏的问题。
  4. 接口修复了1和3,但由于它们只是NILed,(2)需要发生,这不能完成。

    此类问题需要在编译器级别实现。没有它,根本没有足够的事件来实现它。但是请解释一下你想要实现的目标。 有时候对于特定情况,有一些可以解决的问题,即使一般情况不可修复

答案 5 :(得分:1)

有一个肮脏的伎俩:

THackClass = class
private
  function Sum(const A, B: Integer): Integer;
public
  function HackMethod: Integer;
end;

function THackClass.HackMethod: Integer;
begin
  Self := THackClass.Create;
  try
    Result := Sum(2, 3);
  finally
    Self.Free;
  end;
end;

function THackClass.Sum(const A, B: Integer): Integer;
begin
  Result := A+B;
end;

// and then

procedure TForm1.Button1Click(Sender: TObject);
var
  HackClass: THackClass;
begin
  ShowMessage(IntToStr(HackClass.HackMethod));
end;

当然,没有黑客写它会更自然:

TNonHackClass = class
private
  function Sum(const A, B: Integer): Integer;
public
  class function NonHackMethod: Integer;
end;

class function TNonHackClass.HackMethod: Integer;
var
  instance: TNonHackClass;
begin
  instance := TNonHackClass.Create;
  try
    Result := instance.Sum(2, 3);
  finally
    instance.Free;
  end;
end;

function TNonHackClass.Sum(const A, B: Integer): Integer;
begin
  Result := A+B;
end;

// and then

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(TNonHackClass.NonHackMethod));
end;

答案 6 :(得分:0)

正如David所说,你应该从帮助中看看Class方法:

  

大多数方法都称为实例   方法,因为它们在一个上运行   对象的单个实例。一个   class方法是一种方法(除了   对类进行操作的构造函数   而不是对象。那里有两个   类方法类型:普通类   方法和类静态方法。

除了查看类方法之外,您还可以使用现在具有方法能力的记录。

unit test;

interface
uses
  SysUtils,
  Classes;

type
  TMyRecord = record
    FieldA:String;
    FieldB:String;
    procedure MyMethod(const Param1:Integer);
   end;

   procedure DoSomething(const Param:Integer);

implementation

procedure DoSomething(const Param:Integer);
var
  Rec:TMyRecord;
begin
  Rec.MyMethod(Param);  //no constructor needed
end;


procedure TMyRecord.MyMethod(const Param1:Integer);
begin
  //do something coolio here
end;

end.

答案 7 :(得分:0)

你也可以这样做,虽然我不明白你为什么要这样做:

unit Unit2;

interface

type
  TMyClass = class
  public
    class function GetNew: TMyClass;
    function Hello: TMyClass;
  end;


implementation

{ TMyClass }

class function TMyClass.GetNew: TMyClass;
begin
  Result := TMyClass.Create();
end;

function TMyClass.Hello: TMyClass;
begin
  ShowMessage( 'hello' );
  Result := Self;
end;

procedure CallMyClass();
begin
  TMyClass.GetNew.Hello.Free;
  // or
  with TMyClass.GetNew do
  try
    Hello;
  finally
    Free;
  end;
end;