jpfollenius
jpfollenius

Reputation: 16612

Class Types and Constructor Calls

If I write

type
  MyClass = class of TMyClass;
...
Obj := MyClass.Create;

the correct constructor (the one in TMyClass) is called.

If I write

var
  ClassVar : TClass;
...
ClassVar := TMyClass;
Obj := ClassVar.Create;

only the TObject constructor is called.

Why? What's the difference between the two versions? Can I force the TMyClass constructor call in the second scenario?

Upvotes: 2

Views: 406

Answers (4)

Fabricio Araujo
Fabricio Araujo

Reputation: 3820

Or descend it from TComponent, which already have a virtual constructor.

Upvotes: -3

Ozan
Ozan

Reputation: 4415

TObject.Create is not virtual, you need to declare ClassVar as a classtype of a class with a virtual constructor.

Upvotes: 4

Stijn Sanders
Stijn Sanders

Reputation: 36840

I would suggest you look into overriding the AfterConstruction method that's introduced by the TObject to make polymorphism like this work.

Each class definition can introduce a new constructor, with it's own set of parameters. A class variable only knows of the constructor if the base class it's a variable for. This is all possible because a constructor is neither virtual nor overridden. You could flag the constructor virtual on your base-class, and flag all descending classes override, which blocks the parameter list. (I think if you forget 'override' the compiler warns your new constructir hides the virtual one.)

Upvotes: 2

Mason Wheeler
Mason Wheeler

Reputation: 84540

TClass is declared as "Class of TObject" in system.pas. What constructor gets called is decided at compile-time, and all the compiler knows is what base class you're using. It doesn't know what the value of the variable will be when it runs, so it has to default to the base class. If you're using a TClass, then your base class is TObject.

If you're using a class variable, I assume you have some sort of heirarchy and you're trying to implement a factory. If you want to make sure the right constructor gets called based on the value of a class variable at runtime, not something contained in your code at compile time, you need a virtual constructor.

type
  TMyBaseObject = class(TObject)
  public
    constructor Create; virtual;
  end;

  TMyClass = class of TMyBaseObject;

Use a TMyClass instead of a TClass as your class variable, and now the compiler will generate a call to TMyBaseObject.Create, which is virtual. Make sure all your derived classes override the base constructor, and you'll end up calling the right one at runtime.

Upvotes: 11

Related Questions