The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,769 other followers

Answered @ stackoverflow – on virtual constructors called through class references in Delphi

Posted by jpluimers on 2009/04/27

I just tried to elaborate on an answer to a question from Michael Justin on stackoverflow.
(yes, that’s the author of some message broker clients like the Habari ActiveMQ client that allows Delphi applications to talk to the Apache ActiveMQ message queueing broker).

His question is on virtual constructors and class reference: How can I detect if a Delphi class has a virtual constructor?
The combination of class references and virtual constructors is one of the fundaments of how Delphi became Delphi; in simple terms:

  • class references allow you to register components on the component palette in Delphi
  • virtual constructors allows the designer to construct  the instances of those components at design time

That’s why I think it is important to describe the distinction between virtual constructors and regular non-virtual constructors in the answer below (which is a copy of the answer I posted to stackoverflow)

 Michael,

I get your question, but since your sourcecode does not compile, I think you miss the point of your question ;-)

My answer is a bit of an elaboration on what Mason tried to explain in his second answer.

The issue at hand is that your question imples that you have a ‘class reference’ (like TClass or TComponentClass) that references to a base class that has a virtual constructor.
However, TClass doesn’t (TClass references a class that has a non-virtual constructor), but TComponentClass does.

You see the difference when disassembling the call to the constructor by using a class reference.
When you call a virtual constructor through a class reference, the code is slightly different than when you call a non-virtual constructor:

  • calling a virtual constructor has an indirection
  • calling a non-virtual constructor does a direct call

This disassembly shows what I mean:

    TestingForVirtualConstructor.dpr.37: ComponentClassReference := TMyComponentClass;
    00416EEC A1706D4100       mov eax,[$00416d70]
    TestingForVirtualConstructor.dpr.38: Instance := ComponentClassReference.Create(nil); // virtual constructor
    00416EF1 33C9             xor ecx,ecx
    00416EF3 B201             mov dl,$01
    00416EF5 FF502C           call dword ptr [eax+$2c]
    TestingForVirtualConstructor.dpr.39: Instance.Free;
    00416EF8 E8CFCDFEFF       call TObject.Free
    TestingForVirtualConstructor.dpr.41: ClassReference := TMyClass;
    00416EFD A1946E4100       mov eax,[$00416e94]
    TestingForVirtualConstructor.dpr.42: Instance := ClassReference.Create(); // non-virtual constructor
    00416F02 B201             mov dl,$01
    00416F04 E893CDFEFF       call TObject.Create
    TestingForVirtualConstructor.dpr.43: Instance.Free;
    00416F09 E8BECDFEFF       call TObject.Free

So when you have a variable of type class reference for which the constructor is virtual, and you call that constructor through that variable, you are sure that the actual class in that variable will have a virtual constructor.

You can not determine on which actual class that constructor is implemented (well, not without extra debugging info, for instance from the .DCU, .MAP, .JDBG, or other sources).

Here is the example code that does compile:

    program TestingForVirtualConstructor;

    {$APPTYPE CONSOLE}

    uses
      Classes, SysUtils;

    type
      TMyComponentClass = class(TComponent)
        MyStrings: TStrings;
        constructor Create(Owner: TComponent); override;
      end;

    constructor TMyComponentClass.Create(Owner: TComponent);
    begin
      inherited;
    end;

    type
      TMyClass = class(TObject)
        MyStrings: TStrings;
        constructor Create();
      end;

    constructor TMyClass.Create();
    begin
      inherited;
    end;

    procedure Test;
    var
      // TComponentClass has a virtual constructor
      ComponentClassReference: TComponentClass;
      ClassReference: TClass;
      Instance: TObject;
    begin
      ComponentClassReference := TMyComponentClass;
      Instance := ComponentClassReference.Create(nil); // virtual constructor
      Instance.Free;

      ClassReference := TMyClass;
      Instance := ClassReference.Create(); // non-virtual constructor
      Instance.Free;
    end;

    begin
      try
        Test;
      except
        on E: Exception do
          Writeln(E.Classname, ': ', E.Message);
      end;
    end.

To get back to your original question:
When your class reference references a base class having a virtual constructor, you are sure that you will always call a virtual constructor using an indirection.
When your class reference references a base class having a non-virtual constructor, you are sure that you will always call a non-virtual constructor using a direct call.

Hope this sheds some more light on your question.

–jeroen

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

 
%d bloggers like this: