BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Virtual Constructor Hack
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design
View previous topic :: View next topic  
Author Message
Hechicero
Guest





PostPosted: Fri May 13, 2005 1:55 pm    Post subject: Virtual Constructor Hack Reply with quote



Hi,
I really hate that TObject constution is not virtual. Really really
hate it. I have the following problem.

function TMyClass.Build(c : TClass):TObject;
Begin
result := c.Create;
end;

Of course if i call something like

o : TMyClass
....
Button := TMyClass.Create(c);

Fails misserably when I try to use the button because the TButton
Constructor is never executed.grrrrrr

I tryied an ugly custom hack that is making the following class

TVirtualConstructorClass = class of TVirtualConstructor;

TVirtualConstructor= class
constructor create();virtual;abstract;
end;

And then refactoring

function TMyClass.Build(c : TClass):TObject;
Begin
result := TVirtualConstructorClass(c).Create;
end;

So far so good.
The problem is the following.
My guts tells mey that I may have problem issues with the order the methods
are declared (and appear in the VMT)
If I call that function with a class that does not have a virtual
constructor it fails misserably.

Can anyone help me extend that hack?
Is there a way to find out IF the constructor is virtual?


Esteban Calabria

PD: Lets assume for a moment that the constructors dont take parameters.
That may be an issue for another post.


Back to top
Hechicero
Guest





PostPosted: Fri May 13, 2005 2:20 pm    Post subject: Re: Virtual Constructor Hack Reply with quote



Build will be called with classes I read from an String and
I get the class pointer by calling getClass.
The classes in the string could inherit from anything and may or may not
have a common ancestor. May or may not have virtual constructors.
There are about 1000 classes (1000 Build methods in TMyClass (?) ).

So to sorround this problem I program the construction overriding the
AfterConstruction method and imposed the codding standard that the
constructor cannot be touched.

But I´d really like to find a way to be able to create that classes from an
string containing its class name without imposing the standard I talk abour.
How can I call the right constructor?



"Charles McAllister" <charles (AT) avimark (DOT) net> escribió en el mensaje
news:4284b5dc$1 (AT) newsgroups (DOT) borland.com...
Quote:
Hechicero wrote:
Hi,
I really hate that TObject constution is not virtual. Really really
hate it. I have the following problem.

Help is on the way <g>.

function TMyClass.Build(c : TClass):TObject;
Begin
result := c.Create;
end;

Of course if i call something like

o : TMyClass
...
Button := TMyClass.Create(c);

Fails misserably when I try to use the button because the TButton
Constructor is never executed.grrrrrr

Even if it did call TButton's constructor, it would still fail miserably,
since TButton's
constructor requires an Owner parameter.

I think what you need is several overloaded Build methods instead of just
one all encompassing method...

function TMyClass.Build(c: TComponentClass);
function TMyClass.Build(c: TClass);
function TMyClass.Build(c: TMyObjectClass);
etc.

this assumes though that Build knows what the Owner is for the component
you are creating. Or you
could write it like so...

function TMyClass.Build(c: TComponentClass; AOwner: TComponent);

Hope this helps.
Charles



Back to top
Michael Mattsson
Guest





PostPosted: Fri May 13, 2005 2:22 pm    Post subject: Re: Virtual Constructor Hack Reply with quote




Quote:
I really hate that TObject constution is not virtual. Really really
hate it.

if the TObject base class constructor was virtual then ALL the decendant
classes could have to use the same paramater list (in this case none) for
the Create procedure.

This would be a problem for classes such as TComponent (and others) that
pass the instance owner via the parameters:
constructor TComponent.Create(AOwner : TWinControl);

If you look at the TComponent class, you'll see it inherits from the
TPersistant class, which inherits from TObject class.
The TComponent class implements it's own virtual constructor (constructor
Create(AOwner: TComponent); virtual;)

Nothing is stopping you from implementing a virtual constructor in your
classes that inherit from TObject, ex:

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



Michael




Back to top
Hechicero
Guest





PostPosted: Fri May 13, 2005 2:29 pm    Post subject: Re: Virtual Constructor Hack Reply with quote


Quote:
I really hate that TObject constution is not virtual. Really really
hate it.

if the TObject base class constructor was virtual then ALL the decendant
classes could have to use the same paramater list (in this case none) for
the Create procedure.

This would be a problem for classes such as TComponent (and others) that
pass the instance owner via the parameters:
constructor TComponent.Create(AOwner : TWinControl);

If you look at the TComponent class, you'll see it inherits from the
TPersistant class, which inherits from TObject class.
The TComponent class implements it's own virtual constructor (constructor
Create(AOwner: TComponent); virtual;)


Yup, thats another issue. That its why I remarked in the first post that
that :
"Lets assume for a moment that the constructors dont take parameters. That
may be an issue for another post."
For this case lets assume none of the classes constructors takes parameters.



Quote:
Nothing is stopping you from implementing a virtual constructor in your
classes that inherit from TObject, ex:

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

I know... but the class may inherit from TObject or anything in this case.
If I could inherit the all the classes from a TMyCustom i could use
references to TMyCustomClass instead of TClass in the Build method i
described and the problem is solved.

Unforunatelly that is not this case here Sad.





Back to top
Charles McAllister
Guest





PostPosted: Fri May 13, 2005 3:12 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

Hechicero wrote:
Quote:
Hi,
I really hate that TObject constution is not virtual. Really really
hate it. I have the following problem.

Help is on the way <g>.


Quote:
function TMyClass.Build(c : TClass):TObject;
Begin
result := c.Create;
end;

Of course if i call something like

o : TMyClass
...
Button := TMyClass.Create(c);

Fails misserably when I try to use the button because the TButton
Constructor is never executed.grrrrrr

Even if it did call TButton's constructor, it would still fail miserably, since TButton's

constructor requires an Owner parameter.

I think what you need is several overloaded Build methods instead of just one all encompassing method...

function TMyClass.Build(c: TComponentClass);
function TMyClass.Build(c: TClass);
function TMyClass.Build(c: TMyObjectClass);
etc.

this assumes though that Build knows what the Owner is for the component you are creating. Or you
could write it like so...

function TMyClass.Build(c: TComponentClass; AOwner: TComponent);

Hope this helps.
Charles

Back to top
Wayne Niddery [TeamB]
Guest





PostPosted: Fri May 13, 2005 3:31 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

Hechicero wrote:
Quote:
Build will be called with classes I read from an String and
I get the class pointer by calling getClass.
The classes in the string could inherit from anything and may or may
not have a common ancestor. May or may not have virtual constructors.
There are about 1000 classes (1000 Build methods in TMyClass (?) ).

If you want to create objects from their class names, and be sure of the
*correct* constructor being called, then the constructor of all such objects
*must* be virtual - otherwise you will only ever get the base class
contructor being called. If you want to allow for different parameter
signatures, then you will have to have a class type for each different
signature and test for these. You must also start with TPersistent, not
TObject, in order to be able to register the classes.

For example:

TBase = class(TPersistent)
constructor Create; virtual;
end;
TA = class(TBase)
constructor Create; override;
end;
TB = class(TA)
constructor Create(s: string); virtual;
end;

TBaseClass = class of TBase;
TBClass = class of TB;

[...]

procedure TForm1.Make(cn: string);
var bc: TBaseClass;
begin
bc := TBaseClass(FindClass(cn));
if bc = TB then
TBClass(bc).Create('s')
else if bc.InheritsFrom(TBase) then
begin
bc.Create
end
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Make('TBase');
Make('TA');
Make('TB');
end;

[...]

constructor TBase.Create;
begin
ShowMessage('TBase');
end;

constructor TA.Create;
begin
ShowMessage('TA');
end;

constructor TB.Create;
begin
ShowMessage('TB');
end;

initialization
RegisterClasses([TBase, TA, TB]);

--
Wayne Niddery - Logic Fundamentals, Inc. (www.logicfundamentals.com)
RADBooks: http://www.logicfundamentals.com/RADBooks.html
Bandwagons are like streetcars, there'll be another along in a few
minutes.



Back to top
Hechicero
Guest





PostPosted: Fri May 13, 2005 3:54 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

As I answer to Michael Mattson I kwnow that your solution will solve the
problem. As a matter of fact I actually implemented that solution many
times.

Unfortunatelly this case is a little bit different because I cant get all
classes to inherit from a common ancestor. Lets say I have to cannot modify
the source of the classes
(or minimise it without having to modifying 1000 clases by hand).
I work with What I am looking for is a hack to call the correct constructor
from a TClass reference.

I give you an example of a solution I came up with with is better but that
not solve my problem completely
1) I need a proxy for each class (as a matter of fact I have for most of
them and they are auto-generated)
2) Each class (actually an ancestor) should override clasfunction
NewInstance and return the proxy.
3) The proxy create the real class within itself

The thing is that if I override class function NewInstance the best
candidate for that is a base class for every object. And We have the same
problem because I cannot change the base class ( could put virtual if it was
the case).
But the advantage of this is I dont need to override the constructor in each
class.

A better solution but I still have to modify the classes I work with.

Esteban Calabria

PD: I know that adding a base class with virtual constructor and making
every subclass overriding it workds.

PD: Classes can be registered with RegisterClass (if that was not the case I
could use my custom RegisterClass anyway)




Back to top
Michael Mattsson
Guest





PostPosted: Fri May 13, 2005 4:11 pm    Post subject: Re: Virtual Constructor Hack Reply with quote


You know that the problem arises because you are using TClass/TObject which
has no virtual constructor.

the only solutions I can think of are (at the moment):

- to proxy the TObject class - so apps using your component will implement
your version of TObject (presumably with virtual constructor) instead of the
system.pas TObject.
- modify the system.pas file, add the "virtual" modifier to the TObject's
constructor & rebuild your app
- instead of having the Build procedure use a TClass (TClass will never work
as it doesn't have a virtual constructor), you pass a string containing the
name of the passed class, use FindClass and create the object from it
instead.


looks like you are building some type of factory pattern or perhaps a
reflection framework?

Michael


"Hechicero" wrote:
Quote:
As I answer to Michael Mattson I kwnow that your solution will solve the
problem. As a matter of fact I actually implemented that solution many
times.

Unfortunatelly this case is a little bit different because I cant get all
classes to inherit from a common ancestor. Lets say I have to cannot
modify
the source of the classes
(or minimise it without having to modifying 1000 clases by hand).
I work with What I am looking for is a hack to call the correct
constructor
from a TClass reference.

I give you an example of a solution I came up with with is better but that
not solve my problem completely
1) I need a proxy for each class (as a matter of fact I have for most of
them and they are auto-generated)
2) Each class (actually an ancestor) should override clasfunction
NewInstance and return the proxy.
3) The proxy create the real class within itself

The thing is that if I override class function NewInstance the best
candidate for that is a base class for every object. And We have the same
problem because I cannot change the base class ( could put virtual if it
was
the case).
But the advantage of this is I dont need to override the constructor in
each
class.

A better solution but I still have to modify the classes I work with.

Esteban Calabria

PD: I know that adding a base class with virtual constructor and making
every subclass overriding it workds.

PD: Classes can be registered with RegisterClass (if that was not the case
I
could use my custom RegisterClass anyway)







Back to top
Bob Dawson
Guest





PostPosted: Fri May 13, 2005 4:25 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

"Hechicero" wrote
Quote:
I work with What I am looking for is a hack to call the correct
constructor from a TClass reference.

I don't know of any codeless or 'elegant' (single hack that will work for
all classes) solution.

Quote:
I give you an example of a solution I came up with with is better but

My tendency would be to exteriorize this. In other words,

Create a constructor helper object with a virtual class method CreateObject
: TObject

For each class you want to handle, define a descendent that knows how to
contruct that class (supplying default params as necessary)

TButtonConstructor = class(TConstructorHelper)
class function CreateObject : TObject; override;
// as
begin
result := TButton.Create(nil);
end;

Register constructor helper classes under the class name of the target
class:

{singleton}ConstructorHelperRegistry.RegisterHelper(TButton,
TButtonConstructor)

then your factory can internally find the right helper class and have it
return the object wanted.

TGenericFactory.GetObject(AClassName : string) : TObject;
var
helper : TConstructorHelperClass
begin
helper := ConstructorHelperRegistry.GetHelperClass(AClassName);
if assigned(helper) then
Result := helper.GetObject
else Result := nil; //or whatever error handling
end;

bobD



Back to top
Hechicero
Guest





PostPosted: Fri May 13, 2005 4:44 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

Quote:
You know that the problem arises because you are using TClass/TObject
which
has no virtual constructor.

Good.

Quote:

the only solutions I can think of are (at the moment):

- to proxy the TObject class - so apps using your component will
implement
your version of TObject (presumably with virtual constructor) instead of
the
system.pas TObject.

Good. Interesting aproach. How do you propose I proxy the TObject class? I
could achive a lot of good things by doing that
Related to this...It Just came to my mind tricking the names
A unit with

unit redirection;

type

TObject = MyUnit.TMyCustomObject;
TInterfacedPersistent = MyUnit.TMyCustomInterfacedPersistent;
....
(for each vcl class i could possibly inherit from)


That would require adding one uses to each unit that contain the classes...
The big disadvantage I see is that if a procedure takes a TObject
as a paramter it will not take a TMyCustomObject and if a person
outside this groups of units uses this object and passes a TButton as a
parrameter it will complain because TButton doesnt inherit from TMyObject.
mmm... I am not sure I could cope with that


Quote:
- modify the system.pas file, add the "virtual" modifier to the TObject's
constructor & rebuild your app
Hahaha...how many times I was tempted to do something like that. Smile

I will not take that seriously. The system.pas will have to be modified in
every delphi instalation..


Quote:
- instead of having the Build procedure use a TClass (TClass will never
work
as it doesn't have a virtual constructor), you pass a string containing
the
name of the passed class, use FindClass and create the object from it
instead.

Actually I have a method that does that. The problem that or I use getclass
whitin this method or I start to have a method like

Begin
if´ 'tcustomer' then result := Tcustomer.Create;
...
100o lines later it ends
end;

The thing is that the "factory" that creates an object from a TClass
reference has to me totally decoulpled and have no knowledge aboyt the
classes it creates.

Quote:

looks like you are building some type of factory pattern or perhaps a
reflection framework?


Its part of a framework that i designed and many people use. Its mostly a
persistence framework but it has other stuff.
As I said, Right know the construction code is programmed in the
afterConstruction method to overcome the restriction

Esteban Calabria



Back to top
Hechicero
Guest





PostPosted: Fri May 13, 2005 5:06 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

Even If I could make all objets inherit from a base class with virtual
constructor the method that creates the objects would have to know the base
class type. That is exactly what I am trying to avoid.

(That wouldnt happened if the base class just returns the proxy overrifing
the NewInstance, the base class would have to know how to create the proxys
but not otherwise)



Back to top
Charles McAllister
Guest





PostPosted: Fri May 13, 2005 5:15 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

Hechicero wrote:
Quote:
Build will be called with classes I read from an String and
I get the class pointer by calling getClass.
The classes in the string could inherit from anything and may or may not
have a common ancestor. May or may not have virtual constructors.
There are about 1000 classes (1000 Build methods in TMyClass (?) ).

You'll only need 1000 classes if each of those 1000 classes introduces a new static constructor.


if you're trying to automatically create objects that don't have virtual constructors then you won't
be able to create them reliably using a class variable of type TClass, as you've discovered. And
this fact has nothing to do with whether or not these different classes have parameters in their
create constructors or not.

you'll have to have a class type variable for each class in a hierarchy that introduces a static
constructor.

TAClass = class
public
constructor Create;
end;

TAClassClass = class of TAClass;

TBClass = class(TAClass)
public
constructor Create;
end;

TBClassClass = class of TBClass;

TCClass = class(TBClass)
// no new constructor here, so TBClassClass could be used to create
end;

each of these will have to be created like so...

procedure Build(AClassParam: TAClassClass);
begin
AObject := AClassParam.Create;
end;

....and AObject := BClassParam.Create; etc.

There's no other way AFAIK that the correct constructor could be called.

Back to top
Hechicero
Guest





PostPosted: Fri May 13, 2005 5:18 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

Yup... thats the best solution i thought of it but the problem is the
following... I guess the solution may come this way.

The constructor helper will duplicate the number of classes and will take a
lot of time to code but that is not a problem I can generate them
automatically. ( can even have a big factory with methods and call the
methods by reflection. Lets assume methods like create<ClassName>). As A
matter of fact I think that your aproach will solve the problem but... there
is always a but...

The thing is that this way of creating objects is used in many parts in the
program. I could easily mannage the change within the main framework plugin
the autogenerated factory un the framework when the APP starts).
But other parts of the program (that do not interact with the main
framework ) use the TClass reference aproach to create objects. To consider
plugling that factory in every part of the application that uses this
aproach is not straightfoward.

That is why I was hoping to find an alternative hack to avoid that and I was
more prone to the magical cast or the hoocking NewInstance to automatically
return a proxy that creates the real class whithin it.
(The proxy will be autogenerated more or less like theConstructo helpers
factory)

In that way

... (c: TClass;) ..
Begin
c.Create will instantiate a proxy (overriding create instance in the base
class and the proxy will have code like TConcreteClass.Create)

end;

I am still thinkinf if I could improve the solutiona bit...






"Bob Dawson" <bdawson (AT) idtdna (DOT) com> escribió en el mensaje
news:4284d4ea (AT) newsgroups (DOT) borland.com...
Quote:
"Hechicero" wrote
I work with What I am looking for is a hack to call the correct
constructor from a TClass reference.

I don't know of any codeless or 'elegant' (single hack that will work for
all classes) solution.

I give you an example of a solution I came up with with is better but

My tendency would be to exteriorize this. In other words,

Create a constructor helper object with a virtual class method
CreateObject
: TObject

For each class you want to handle, define a descendent that knows how to
contruct that class (supplying default params as necessary)

TButtonConstructor = class(TConstructorHelper)
class function CreateObject : TObject; override;
// as
begin
result := TButton.Create(nil);
end;

Register constructor helper classes under the class name of the target
class:

{singleton}ConstructorHelperRegistry.RegisterHelper(TButton,
TButtonConstructor)

then your factory can internally find the right helper class and have it
return the object wanted.

TGenericFactory.GetObject(AClassName : string) : TObject;
var
helper : TConstructorHelperClass
begin
helper := ConstructorHelperRegistry.GetHelperClass(AClassName);
if assigned(helper) then
Result := helper.GetObject
else Result := nil; //or whatever error handling
end;

bobD





Back to top
Bob Dawson
Guest





PostPosted: Fri May 13, 2005 5:32 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

"Hechicero" wrote
Quote:
That is why I was hoping to find an alternative hack to avoid that
and I was more prone to the magical cast or the hoocking NewInstance

Evin if such a hack is possible, I certainly don't know it.

Might try posting a help request into the .delphi.language.ojectpascal
newsgroup. Seems to me it's more a language issue than an oodesign issue.

bobD



Back to top
Hechicero
Guest





PostPosted: Fri May 13, 2005 5:41 pm    Post subject: Re: Virtual Constructor Hack Reply with quote

I was planning to post the thread also there.

I was open to a design solution and a hack solution that is why I posted
here. If I find a design solution it would be better than a hack.

So far it was useful cos I got the proxyies idea. Working on it.




Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design All times are GMT
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.