I was wondering if it is possible to have an object instance without calling any constructor directly. Something like that:
var
aObject : TMyObj开发者_Go百科ect;
begin
aObject.MyMethod; //will cause an AV, but is it possible?
end;
Edit:
I know about static methods, but thats is not what i am looking for. I am looking for an way to get the constructor called without having to explicit call it.
Delphi's objects are all heap-allocated: you can't simply declare an object and call methods on it, like you could do in C++ for example, you have to call an constructor to allocate and set up memory. But note even in C++ you are actually calling an constructor when you do that!
Maybe you can get away with a record and not an object? Example:
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;
This is weird, as you know. But, so long as the method is static and doesn't refer to Self, then this will work.
Of course, such a thing is better known as a class method. Perhaps that's what you want?
type
TMyObject = class
class procedure MyClassMethod;
end;
...
TMyObject.MyClassMethod;
EDIT
You edited your question. Apparently you know all about static methods. You don't want to call a method on an uninitialized object.
In fact, you now state that you want the act of calling a method on an un-initialized object instance to result in the instance being created and the method being called.
This is not possible. There's no magic anywhere that calls constructors for you.
There's a dirty trick:
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;
Of course, it would be more natural to write it without the hack:
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;
You can "allocate" an object by using:
class function NewInstance: TObject; virtual;
This function allocates and initializes the object. After that, you can call the "create" constructor as a normal function on it (this is how constructor Create works when you dive into the assembly/CPU view)
Delphi - unlike for instance C++ - does not have a default way to automatically create constructors.
It has to do with how Delphi manages variables and scope.
In C++, when a variable comes into scope, it automatically calls the constructor.
What you are after is RAII (Resource Acquisition Is Initialisation).
Barry Kelly (one of the Delphi compiler engineers) wrote an interesting article about RAII in Delphi.
His solution is based on the automatic refcounting of interfaces in Delphi.
Explaining this would basically mean to copy/paste his article, so please follow the above link and read it.
--jeroen
No. There are actually several problems:
- you need to some how initialize the variable. Either to create the object, or to NIL it, so that the method can safely detect if the variable has been created or not
- If (1) doesn't create the object, the method invokation needs code to be generated to see if the object is created, and create it if necessary.
- Then there is the problem of destruction.
Interfaces fix 1 and 3, but since they are only NILed, (2) needs to happen, which can't be done afaik.
Such issues need to be implemented on compiler level. Without that, there are simply not events enough to implement it. But please do explain what exactly you want to achieve. Sometimes for specific cases, there are bearable workarounds, even if the general case is not fixable
As David said, you should look at Class methods, from the help:
Most methods are called instance methods, because they operate on an individual instance of an object. A class method is a method (other than a constructor) that operates on classes instead of objects. There are two types of class methods: ordinary class methods and class static methods.
Besides looking at class methods, you could use records, which now have the ability for methods.
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.
You could also do something like this, though I fail to see why you would want to:
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;
精彩评论