null
null

Reputation: 3517

Delphi 'class of' use to create an object of a specific type

I have TParentObj = class(TComponent) and TChildObj = class (TParentObj). In addition I have a TCustomObj = class of TParentObj.

I'm then wanting to create an object of Type parent OR Type Child depending on what a variable is. If 'child' is selected then a TChildObj should be created and so on.

In the function I have a var: obj : TCustomObj. and then I'm trying to do:

if oReturnType = TChildObj
  obj := TChildObj.create
else if oReturnType = TParentObj
  obj := TParentObj.create

oReturnType is set and passed in elsewhere.

If I use 'is' instead of '=' I receive the error that the operator is not applicable to this operand type and if I use = instead I get an incompatible types error between TCustomObj and both TChildObj and TParentObj.

I've searched quite a bit but have yet to discover what I'm doing wrong and hoping someone here might be able to shed some light on it.

Thanks in advance.

Upvotes: 1

Views: 2291

Answers (2)

Mason Wheeler
Mason Wheeler

Reputation: 84540

First off, it appears that you've missed one of the most important points of TClass variables: they have access to constructors, and to virtual constructors.

If you put a constructor on TParentObj and declare it virtual;, and then have all descendants override; that constructor as needed, then a TClass variable declared as class of TParentObj will have access to this virtual constructor, and will behave exactly as you'd expect a virtual method to behave:

obj := oReturnType.Create(); 
//invoke the virtual constructor on the actual type of oReturnType

This technique is used extensively in the VCL; it's at the core of Delphi's form streaming system, for example. TComponent defines a virtual constructor whose signature is (AOwner: TComponent), and every custom component and control that needs a new constructor overrides this one. It's a very useful system, and if you look at the way it works you'll quickly gain an appreciation for the techniques involved.

But as for the actual problem, you're getting an incompatible types error between TCustomObj and both TChildObj and TParentObj because they're not compatible types.

TChildObj and TParentObj are object classes, and TCustomObj is a metaclass, or class variable. A TParentObj variable represents an object, whereas TCustomObj, which is defined as class of TParentObj, represents the class itself, not an object of that class. Declare obj as TParentObj (which will accept an object instance of TParentObj or any of its descendants) and you'll be good.

Upvotes: 4

Sir Rufo
Sir Rufo

Reputation: 19096

You can use the classtype TCustomObj to create the instance

function ObjFactory( AClass : TCustomObj ): TParentObj;
begin
  Result := AClass.Create;
end;

procedure foo;
var
  LObj : TParentObj;
begin
  // instance of TParentObj
  LObj := ObjFactory( TParentObj );
  // or instance of TChildObj
  LObj := ObjFactory( TChildObj );
end;

Upvotes: 2

Related Questions