Recent

Author Topic: Casting Variables and pointers  (Read 4187 times)

aljgardin

  • Newbie
  • Posts: 5
Casting Variables and pointers
« on: December 11, 2018, 02:28:19 am »
Is there a way to cast variables with AS or hard cast to a another variable.
ie..

type
TClassOne = class(TComponent);

TClassTwo = class(TClassOne);

TClassThree = Class(TClassTwo);

TMyClassClass = Class of TClassOne;

var
  aObject: TObject;
  aClass: TClass;
  aClassThree: TClassThree;
begin
  aClass := TClassThree;
  aObject := aClass.NewInstance;

// None of the below work or similiar
  aClassThree := aObject as aClass;
  aClassThree := aObject as aClass.ClassType;
end;


lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Casting Variables and pointers
« Reply #1 on: December 11, 2018, 03:31:03 am »
Quite logically, you can only cast a descendant to an ancestor type not viceversa.

The ancestor object hasn't got the space needed to "emulate" a decendant's fields, neither the pointers in the VMT for its (new) methods, etc.

ETA

Also, note that as must be resolvable in compile time; it's used in constructions such as:
Code: Pascal  [Select][+][-]
  1. aClassThree := aObject as TClassThree;
  2. { Or using the alternate sintax: }
  3. aClassThree := TClassThree(aObject);

Hint: What's the error you're receiving?
« Last Edit: December 11, 2018, 03:45:33 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
Re: Casting Variables and pointers
« Reply #2 on: December 11, 2018, 03:45:58 am »
Is there a way to cast variables with AS or hard cast to a another variable.
ie..

type
TClassOne = class(TComponent);

TClassTwo = class(TClassOne);

TClassThree = Class(TClassTwo);

TMyClassClass = Class of TClassOne;

var
  aObject: TObject;
  aClass: TClass;
  aClassThree: TClassThree;
begin
  aClass := TClassThree;
  aObject := aClass.NewInstance;

// None of the below work or similiar
  aClassThree := aObject as aClass;
  aClassThree := aObject as aClass.ClassType;
end;
What are you trying to accomplish? The code is all over the place and I can't figure out your goal. here are a few hints.
1) Tclass is defined as Class of Tobject. This types of variables only save the class reference for dynamic object creation, it is not to be used to save or access objects.
2) To create an object you call its contractor usually named create eg.
Code: Pascal  [Select][+][-]
  1. var
  2.   vClass: TClassone;
  3. begin
  4.   vClass := TClassThree.Create;
  5.   showmessage(vClass.ClassName);
  6.   vClass.free;
  7. end;
  8.  


aljgardin

  • Newbie
  • Posts: 5
Re: Casting Variables and pointers
« Reply #3 on: December 12, 2018, 04:05:16 am »
Thank you.

  My Mistake, All Classes should have been of type TClassOne.
Actual code is long and in multiple units.

ETA answered what I was Sure was the answer.

aClassThree := aObject as TClassThree;
{ Or using the alternate sintax: }
aClassThree := TClassThree(aObject);

Also, note that as must be resolvable in compile time; -->> I could not find this in documentation.

Was hoping for Some kind of Magic.
  Wanted to replace TClassThree above with a Variable.



HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
Re: Casting Variables and pointers
« Reply #4 on: December 12, 2018, 05:06:31 am »
Thank you.

  My Mistake, All Classes should have been of type TClassOne.
Actual code is long and in multiple units.

ETA answered what I was Sure was the answer.

aClassThree := aObject as TClassThree;
{ Or using the alternate sintax: }
aClassThree := TClassThree(aObject);

Also, note that as must be resolvable in compile time; -->> I could not find this in documentation.
"as" is a runtime construct it does not resolve at compile time. It is a two step process first it checks if its safe for the variable aobject to be used as a TClassThree and raises an exception if it is not if it is it then continues with the assignment.
The "alternate" syntax is a hard cast that takes place with out any checks or errors the compiler only generates the assignment code assuming that the programmer knows that the cast is safe. the two although equivalent in most case they  are not equal.
Was hoping for Some kind of Magic.
  Wanted to replace TClassThree above with a Variable.
magic of what? you can assign any object to any other object, regardless of type, using pointers, if that is what you are after, but knowing nothing about the use case I can not recommend any of the above let alone tell which is appropriate.

damieiro

  • Full Member
  • ***
  • Posts: 200
Re: Casting Variables and pointers
« Reply #5 on: December 12, 2018, 08:25:53 am »
I do not understand what do you want.

I think of classes like typed pointers. It seems like that you interchange different kind of pointers with no reason and the data inside these will be a mess.

Then you say your code is different in next posts  (all are TObjectOne or so).

Could you put the last code (and with the [code =pascal] [/ code] for readability) please?

Is something like this? Could you clarify it, please?
Code: Pascal  [Select][+][-]
  1. type
  2.   TClassOne     = Class(TComponent);
  3.   TClassTwo     = Class(TClassOne);
  4.   TClassThree   = Class(TClassOne); {Not two}
  5.   MyClassClass  = Class of TClassOne;
  6.  
  7. var
  8.   aObject: TObject;
  9.   aClass: TClass;   {TClassOne? Tobject?MyClassClass?}
  10.   aClassThree: TClassThree;
  11.  
  12. begin
  13.   aClass := TClassThree; {TclassThree.Create? is nil assigment :?}
  14.   aObject := aClass.NewInstance; {why not TObject.Create?}
  15.  
  16. // None of the below work or similiar
  17.   aClassThree := aObject as aClass;
  18.   aClassThree := aObject as aClass.ClassType;
  19. end;
« Last Edit: December 12, 2018, 10:56:21 am by damieiro »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Casting Variables and pointers
« Reply #6 on: December 12, 2018, 09:36:30 pm »
Code: Pascal  [Select][+][-]
  1. aObject := aClass.NewInstance; {why not TObject.Create?}

NewInstance() does not take constructors into account.  Which is important in this case, since TClassOne derives from TComponent, whose constructor takes an Owner as an input parameter.  So you need to use something more like this instead:

Code: Pascal  [Select][+][-]
  1. aObject := MyClassClass(aClass).Create(DesiredOwner);
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

aljgardin

  • Newbie
  • Posts: 5
Re: Casting Variables and pointers
« Reply #7 on: December 13, 2018, 01:48:52 am »
Sorry everyone.
I found my mistake.
I am considering this closed.

damieiro

  • Full Member
  • ***
  • Posts: 200
Re: Casting Variables and pointers
« Reply #8 on: December 13, 2018, 08:56:14 am »
@Remy: thanks for the response, but it won't be the same?. TObject create is an empty method, so it will get the getmen too like new instance. Same for the tree/branches of .create to TComponent.  And it won't be called with parameters.. so it won't go for the Aowner way (no matching constructor). But yes, i see your point and i did not take it into account what you say (the Aowner way) and it's right your point :).

Quote

    Code: Pascal  [Select]

        aObject := aClass.NewInstance; {why not TObject.Create?}


NewInstance() does not take constructors into account.  Which is important in this case, since TClassOne derives from TComponent, whose constructor takes an Owner as an input parameter.  So you need to use something more like this instead:

Code: Pascal  [Select]

    aObject := MyClassClass(aClass).Create(DesiredOwner);
« Last Edit: December 13, 2018, 09:11:14 am by damieiro »

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Casting Variables and pointers
« Reply #9 on: December 13, 2018, 11:15:17 am »
The newinstance code just allocates memory but it calls through to initinstance.
What you call an *empty* constructor actually sets up the VMT (and a bit more). It is not really empty because it is responsible to call initinstance and newinstance....
I see the documentation is wrong here, which says "it does nothing". I will file a report against the documentation. https://www.freepascal.org/docs-html/rtl/system/tobject.create.html
It implies the above so it does do something.... You can also see that in the debugger. It first calls newinstance (which is virtual) which then calls initinstance which returns the pointer to the object through the default constructor which  assigns it to a variable.
[edit] done, mantis 34699
« Last Edit: December 13, 2018, 11:35:26 am by Thaddy »
Specialize a type, not a var.

damieiro

  • Full Member
  • ***
  • Posts: 200
Re: Casting Variables and pointers
« Reply #10 on: December 13, 2018, 11:47:37 am »
Thanks Thaddy. :)

Another doubt.. the constructor (keyword) itself then do this (is order correct?):
- setups the VMT
- allocates memory by newinstance, initinstance.
- do the code in constructor method.
- calls .aftercreation method .

Newinstance:
- allocates memory. (no vmt, no aftercreation...)

Is this correct?
« Last Edit: December 13, 2018, 11:49:11 am by damieiro »

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Casting Variables and pointers
« Reply #11 on: December 13, 2018, 02:27:15 pm »
Order is:
1. Default constructor TObject.Create calls TObject.NewInstance.
2. NewInstance  allocates the memory and then calls TObject.InitInstance. Note that NewInstance is virtual: the memory can come from anywhere!! when you override it.
3. InitInstance initializes the memory and also initializes the VMT.
4. Finally the constructor can set the pointer to an instance variable.

So it would be technically possible to use TObject.NewInstance instead of TObject.Create but this is not recommended since indeed the AfterConstruction   is never called..
« Last Edit: December 13, 2018, 02:51:41 pm by Thaddy »
Specialize a type, not a var.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: Casting Variables and pointers
« Reply #12 on: December 13, 2018, 08:20:48 pm »
@Remy: thanks for the response, but it won't be the same?

No, it is not the same.  NewInstance() merely allocates memory for the object and initializes its VMT, but it is the constructor that initializes the object's class members.  Granted, the base TObject constructor is empty, but descendant constructors (like for TComponent) are not.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018