开发者

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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜