2

How can parent procedure call it's child's procedure which was override from itself?

type
  TBase = class(TForm)
  procedure BtnRefreshClick(Sender: TObject);
  protected
    text: string;
end;

procedure TBase.BtnRefreshClick(Sender: TObject);
begin
  showmessage(text);
end;

type
  TParent = class(TBase)
  protected
    procedure doThis;
  end;

procedure TParent.doThis;
begin
  // blah blah do something
  BtnRefreshClick(nil);
end;

type
  TChild = class(TParent)
  procedure BtnRefreshClick(Sender: TObject);
  protected
    procedure clicky; override;
  end;

procedure TChild.BtnRefreshClick(Sender: TObject);
begin
  text := 'Hello, World!';
  inherited;
end;

Actual calling procedure will be somewhat like :

child := TChild.Create;
child.doThis;

If I try to do child.BtnRefreshClick; then it will produce a dialog of Hello, World! since TChild.BtnRefreshClick was called and the text variable were set.

But when I call child.doThis it will only shows an empty dialog box since child.doThis calls parent.doThis and then ??.BtnRefreshClick. How to make parent.doThis call child.BtnRefreshClick? Is it not possible?

Thanks in advance,
Yohan W.

saintfalcon
  • 107
  • 2
  • 15
  • 1
    What you are saying does not match your code. If the instance is a TChild then doThis will call TChild.Clicky because this method is virtual and overridden. Also while you are talking about two different doThis methods I only see one. – Stefan Glienke Mar 24 '14 at 18:08
  • This makes very little sense. You are already using a virtual method that is overridden. I suggest you show the real code instead of this fake code. An SSCCE would be ideal. – David Heffernan Mar 24 '14 at 18:09
  • 1
    @StefanGlienke : Not really. `clicky` is actually `TdxBarButton.onClick` event on TParent's parent class. `doThis` is my custom protected virtual procedure stated in TParent class and called from TChild. – saintfalcon Mar 24 '14 at 18:20
  • @DavidHeffernan : sorry, what is "SSCCE" means? I'd share the .pas file if needed. – saintfalcon Mar 24 '14 at 18:21
  • 1
    You can answer that question with a trivial websearch. Please don't think think that SO replaces websearch. But it is utterly pointless postink fake code. Don't do that. – David Heffernan Mar 24 '14 at 18:25
  • 2
    BtnRefreshClick is obviously an event handler to the btnRefresh and you are using form inheritance. It might be possible to mark the BtnRefreshClick method as virtual (untested) or you can just call btnRefresh.Click to trigger the correct event handler. – Stefan Glienke Mar 24 '14 at 18:30
  • @DavidHeffernan Actually his code makes sense if you think a few seconds about it. If you are for quick score, move on -.- – Stefan Glienke Mar 24 '14 at 18:32
  • @DavidHeffernan : don't do what? SO replaces websearch? I was not posting a fake code, just simplified my code -- as in SSCCE (but not compileable though)? – saintfalcon Mar 24 '14 at 18:32
  • Don't post fake code. Post an SSCCE. And no, SO does not replace websearch. – David Heffernan Mar 24 '14 at 18:33
  • @Stefan If all you care about is quick rep and you'd be satisfied with the question as it is, and can work out what was meant to be asked, then please feel free to answer. I believe that part of what SO can do is impress on people the need to think and write clearly. And ask good questions. – David Heffernan Mar 24 '14 at 18:35
  • 2
    @StefanGlienke : yes, it is solved. just do as you said to call `btnRefresh.click` instead of `btnRefreshClick(nil)`. thanks a lot. @DavidHeffernan : very well then, I shall take my leave on asking question on SO since my question is not good enough to be displayed on SO. – saintfalcon Mar 24 '14 at 18:47
  • @saint You just need to learn how to ask questions better. Then you'll find that half the time you won't even need to ask. Because defining the problem clearly makes it easy to solve. Posting fake code that does not illustrate the problem helps nobody. You surely can see that. – David Heffernan Mar 24 '14 at 18:55

2 Answers2

6

The parent class calls the base class's method because that's the only method that existed within the scope of the parent class. When the compiler compiled the TParent code, it bound the name BtnRefreshClick to the method in the base class, not the one in the child class, because the child class is not an ancestor of the parent.

In general, for a parent object to call a method of a child class, that method should be declared in the parent object (or higher) and be virtual. If you change TBase to make BtnRefreshClick virtual, and you change TChild to override that same method, then when TParent.doThis calls it, the call will be dispatched to the TChild method.

type
  TBase = class(TForm)
    procedure BtnRefreshClick(Sender: TObject); virtual;
  end;

  TChild = class(TParent)
    procedure BtnRefreshClick(Sender: TObject); override;
  end;

In the particular case of a form with method properties assigned by name via DFM settings, another solution is as Saintfalcon's answer demonstrates, which is to call the associated button's Click method. When the button on the TChild form is instantiated, the VCL reads the DFM resource and finds the string "BtnRefreshClick" associated with the button's OnClick event. It uses the form's MethodAddress function to look up the address of the method with that name, and it finds the one belonging to TChild. It assigns that value to the OnClick property. The Click method reads that property and calls whatever method is there.

I've written before about the differences between calling an event-handler method directly, calling the event-handler property, and calling the event trigger, but at that time, I hadn't considered the aspect illustrated here, where a handler is hidden or overridden in a descendant class.

Community
  • 1
  • 1
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
3

As stated by @StefanGlienke to use btnRefresh.click

procedure TParent.doThis;
begin
  // blah blah do something
  // BtnRefreshClick(nil); // this will call TBase.BtnRefreshClick
  btnRefresh.Click; // use this instead to call TChild.BtnRefreshClick
end;

Thank you

saintfalcon
  • 107
  • 2
  • 15
  • +1: good you checked the solution worked. Note that when you have a different `OnABC` event where the component has no `ABC` method you can call, then the suggestion by @StefanGlienke to make `MyControlABC` method (in your case `BtnRefreshClick`) a `virtual` one and override each `MyControlABC` in descendant classes also works. Boy I wish we had a guy like John Skeet here. He has rep and manners that help to positively encourage people writing better questions and answers. Thanks for being persistent! – Jeroen Wiert Pluimers Mar 24 '14 at 18:56
  • @Jeroen As I understand it, that comment is directed at me. I don't think it helps to tell askers that their questions are fine when they are not. Even now it has broken and fake code. When they ask what SSCCE is, I believe that they should be encouraged to do a websearch. I know from previous comments that you prefer to do the websearch for them and provide the links and summarise those links. I don't think that it helps to ignore bad questions and let the askers continue thinking that it is fine to ask like that – David Heffernan Mar 24 '14 at 19:18
  • @Jeroen If a co-worker came to me with fake code they would be sent away and told to return with real code. Which they would do. And they would not make the mistake twice. – David Heffernan Mar 24 '14 at 19:18
  • @David It was not directed at you. It was directed at the Delphi community at large to get more people here coaching people in a positive way to get better at writing questions and answers. I've coached quite a few people at clients to write better code. Not by aiming at their mistakes, but by starting at the things they do well and improving from there. That works really well, and now a few of them help coach others as well. saintfalcon did well by starting to write a question in the first place. – Jeroen Wiert Pluimers Mar 24 '14 at 19:25
  • @Jeroen I agree with much of that, but I think that approach can be taken too far. If people are not told what is wrong with their questions, what incentive is there to improve? Likewise if people edit questions to improve them. The asker here actually did try hard but the code in the original question was so far from the problem, it was hard to remedy. The take away message is to write an SSCCE, and test it immediately before posting. Tbc. – David Heffernan Mar 24 '14 at 19:34
  • We've all posted fake code, sometimes through ignorance and often through sloppiness. That's my usual failing. And then we get ripped for it. Painful, but it does serve to deter future fake posting. I know I am always scared of posting bogus code and get lacerated! I think there needs to be a balance between positive feedback, and tough love. – David Heffernan Mar 24 '14 at 19:35
  • @David two things: Fear is a bad advisor. Working on the positive side has a far greater potential than working on the negative side (Usually the negative side gets weaker when the positive side improves.) But we're going way too much meta here for the question at hand. – Jeroen Wiert Pluimers Mar 24 '14 at 19:41
  • @JeroenWiertPluimers Yes, too meta, but an interesting debate to be sure. My final comment would be that if there is no fear, no realisation that something is wrong, it's hard to improve. That's the tough love. A bit of criticism, but combined with guidance on how to improve. – David Heffernan Mar 24 '14 at 19:43