Delphi - Create instance of subclass
I have a class defined as:
TfraFrame = class(TFrame);
then I have several subclasses all inherting from this, such as:
TfraUsers = class(TfraFrame);
TfraGroups = class(TfraFrame);
TfraMenus = class(TfraFrame);
In my main form i have declared variables as:
var
fraUsers: TfraUsers;
fraGroups: TfraGroups;
fraMenus: TfraMenus;
Now my question is, I would like to have one single function to control the generation of the instances of each class. There should only be once instance o开发者_如何学运维f each class, but i only want to create the instances if the user requires them.
I would like to pass the variable like this:
procedure ShowFrame(Frame: TfraFrame)
begin
if Frame = nil then
begin
Frame := TfraFrame.Create(self);
Frame.Init(Panel1);
end;
Frame.Show;
end;
and call it like this;
ShowFrame(fraUsers);
I was expecting it to create a instance of TfraUsers
(because that is what fraUsers
is declared as), however, i suspect it may be creating an instance of fraFrame
.
Is there a way to create an instance of the type that the variable was declared as?
Yep, you need to tell showFrame which class to instantiate:
add
type
tfraFrameClass = class of TfraFrame;
just after the declaration of tfraFrame. And change showFrame to:
function ShowFrame(Frame: TfraFrame; FrameClass: TfraFrameClass): TfraFrame;
begin
if Frame = nil then
begin
Result := FrameClass.Create(self);
Result.Init(Panel1);
end
else
Result := Frame;
Result.Show;
end;
Note that you cannot pass Frame as a var parameter as the compiler will insist on declared and actual types of the passed parameter to be exactly the same.
Update Updated example to show frame when it was already assigned.
Update I neglected to mention that assigning the result of the Create call in the OP's code for the showFrame procedure wouldn't work. If it wasn't declared as var, the assignment would not go beyond the scope of the showFrame procedure, the value of the variable passed into showFrame would not be changed. Declaring it as a var would not work either as mentioned above. The solution is to do what @Andreas suggests: use an untyped pointer; or make it a function as I did. Of course (grin) I prefer mine as that preserves type safety just a little bit better.
Also, of course in my example the intention was to have the result of the showFrame function assigned to the appropriate frame variable, like so:
fraUsers := showFrame(fraUsers, TfraUsers);
Update Or, as Sertac pointed out, you can still use procedure with a var parameter when you do a cast on the variable you pass to showForm.
procedure showFrame(var Frame: TfraFrame; FrameClasse: TfraFrameClass);
begin
if Frame = nil then
begin
Frame := FrameClass.Create(self);
Frame.Init(Panel1);
end;
Frame.Show;
end;
and call it as:
showFrame(TfraFrame(fraUsers), TFraUsers);
I suggest that you make your frame variables properties
property fraUsers: TfraUsers read GetfraUsers write ffraUsers;
..
function GetFraUsers: TFraUsers;
begin
if fFraUsers = nil then
fFraUsers := TfraUsers.Create(...);
Result := ffraUsers;
end;
Then
procedure ShowFrame(Frame: TfraFrame)
begin
Frame.Init(Panel1);
Frame.Show;
end;
procedure form1.Button1Click(...)
begin
ShowFrame(fraUsers); // creates the frame if it does not exist
end;
精彩评论