INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Help me understand TClass

Help me understand TClass

(OP)
Hi all,

I thought I knew how this worked, but recently encountered something that threw me. Could you please help me understand what's going on?

The sample code below creates a fresh copy of an existing object.

CODE

type
  TBaseObject = class
  private
    FFlag : Boolean;
  public
    constructor Create; virtual;
  end;

  TMyObject = class(TBaseObject)
  public
    constructor Create; override;
  end;

  TMyClass = class of TBaseObject;

constructor TBaseObject.Create;
begin
  inherited;
end;

constructor TMyObject.Create;
begin
  inherited;
  FFlag := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  a : TBaseObject;
  b : TObject;
begin
  a := TMyObject.Create;
  b := a.ClassType.Create;  // a.ClassType = TMyObject
  try
    CheckBox1.Checked := a.FFlag;
    CheckBox2.Checked := TBaseObject(b).FFlag;
  finally
    b.Free;
    a.Free;
  end;
end; 

In this example, only the CheckBox1.Checked = True;

I can fix this by changing the line that creates the b object to

CODE

b := TMyClass(a.ClassType).Create; 

With this change, both checkboxes are checked. But I don't understand why.

Thanks for your help.

RE: Help me understand TClass

I compiled your code as a console app, and put writelns before the assigns and in the constructors.

The original code you posted.

CODE

a assigned
MyObject created.
Base object created.
b assigned 

Your change.

CODE

a assigned
MyObject created.
Base object created.
b assigned
MyObject created.
Base object created. 

The second one is showing up as checked because you are creating another TMyObject class in the second case, as opposed to the TBaseObject in the first case.

But the short answer is that a.ClassType is the descendant class (TMyObject) of the class you use in TMyClass (TBaseObject). As it is the base class of TMyObject, there is no problem behind the *implementation* of the code (though the idea is off, obviously), and TMyObject is getting created, and in process setting the flag. Now if you present different classes (say I make TMyClass a class of TEdit), then I'll get an access violation.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.

RE: Help me understand TClass

Because you are using class references to construct b, the compiler looks for the most common denominator when deciding which constructor to use. In your first case, you declared b to be a TObject, and that is the base of all classes declared with a "class" declaration, so that is the constructor used for b. In the second, you forced the compiler to use TBaseObject's constructor with the typecast.

RE: Help me understand TClass

I wish they would let you pull posts in here. My understanding was incorrect too. I am still trying to work it out. I do know that the documentation says to use the Keywords "is" and "as" instead of ClassType for working with Class references. It also says not to use ClassType in application code, I guess because of inconsistencies on how it is implemented.

RE: Help me understand TClass

After a little more research, I have found this out: You need to overload the ClassType function in your TBaseClass to return a TMyClass pointer, like so:

CODE

interface
type
  TMyClass = class of TBaseObject;

  TBaseObject = class
  private
  public
    FFlag : Boolean;
    constructor Create;virtual;
    function ClassType:TMyClass;overload;inline;
  end;

  TMyObject = class(TBaseObject)
  public
    constructor Create;override;
  end;

implementation

constructor TBaseObject.Create;
begin
  inherited;
end;

constructor TMyObject.Create;
begin
  inherited;
  FFlag := True;
end;

function TBaseObject.ClassType:TMyClass;
begin
  Pointer(Result) := PPointer(Self)^;
end;
end. 

Your classes are all descended from TObject, which has implements the ClassType function such that it returns a TObject for a class type. If not overloaded, the class type will return the closest implementation of ClassType, or TObject in this case. Once you implement the overloaded ClassType function, because TBaseObject's constructor is declared virtual and TMyClass's is an override of TBaseClass's, TMyClass's constructor will be the one that will be called in your program, even though the ClassType returned is TBaseObject. TObject's constructor is not virtual, which is why your first version did not work as you expected.

RE: Help me understand TClass

(OP)
Hi guys,

Thanks for your time looking at this. You've both arrived at the same conclusion - even though a.ClassType = TMyObject, Delphi is creating a TObject instead - confirmed again because if I declare b as a TBaseObject instead of TObject, it won't compile because the assignment is trying to assign a TObject to b.

RE: Help me understand TClass

a.ClassType does NOT = TMyObject, unless you overload the ClassType function in TBaseObject to return a TMyClass; that was the whole point of my most recent post. In your original Code, a.ClassType = TObject, not TMyObject, because you have not overloaded it. I suppose this is why the documentation strongly discourages the use of ClassType, as it is not guaranteed to be implemented and so will result in inconsistent behavior.

RE: Help me understand TClass

(OP)
If I set up a breakpoint on the line where b is assigned, and then add a watch for a.ClassType, it evaluates to TMyObject. Thus my confusion.

RE: Help me understand TClass

The TObject ancestor method returns a dereferenced self pointer as a TObject class. Since the Class reference's address is the same as the actual object (since any object type declared with a "class" declaration are descended from TObject, and therfore IS a TObject), my guess is the debugger probably interprets that as being the same class as the actual object. I do know that even if you overload the ClassType function to return a TMyBaseObject class reference, the debugger still shows a.ClassType as TMyObject. But the Compiler will only "see" the TObject being returned by TObject.ClassType, so that is the Constructor that gets called for b, since TObject's constructor is not declared as virtual.

I hope all this has helped you to a better understanding of what is going on.

RE: Help me understand TClass

(OP)
That makes more sense. You've been a great help. Thank you.

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close