3

I'm writing a class with some virtual/abstract procedures which I expect to get overridden. However they might not be overridden as well, which is also fine. The problem is finding out whether one of these procedures was actually overridden or not. If they're not overridden, I shouldn't try to call those procedures, and need to go about something different instead. If I try to call one of them and isn't overridden, I get Abstract Error.

Is there a way I can detect whether these procedures were overridden or not?

Here's a sample of how they're declared:

type
  TMyClass = class(TObject)
  protected
    procedure VProc; virtual;
    procedure VAProc; virtual; abstract;
  end;
Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • i think your methods have to be virtual and raising exception.. and if call of method raised that exception - method was not overriden like calling abstact method raises `EAbstractError`. – teran Feb 26 '12 at 14:12
  • Still in Debug mode, I get `Abstract Error`... – Jerry Dodge Feb 26 '12 at 14:15
  • if you declare method as `abstract` - it has to be overriden in descendant class. make all of them `virtual` and declare your own exception type. – teran Feb 26 '12 at 14:17
  • 6
    Try this question [How i can determine if an abstract method is implemented?](http://stackoverflow.com/questions/8305008/how-i-can-determine-if-an-abstract-method-is-implemented) – RRUZ Feb 26 '12 at 14:19
  • 5
    Fix the disease and not the symptom. – David Heffernan Feb 26 '12 at 14:36
  • 3
    This sounds like bad design to me. An overridden method that just calls the base method with the same parameters should not have an effect. The only legitimate reason for this test I can think of is as a performance optimization. – CodesInChaos Feb 26 '12 at 15:46
  • Is it vague Q of the month entry? *How to **ensure** case of `X`, but case of `!X` is fine too*. – OnTheFly Feb 26 '12 at 16:53
  • 2
    @Jerry You really are doing this wrong. If you want to call a method, don't make it abstract. If you want calling a method to have no effect, simply implement it as a do nothing method. Trying to detect at runtime whether or not an abstract method has been implemented is a terrible idea. Sorry to say it so harsh but that's really how it is. – David Heffernan Feb 26 '12 at 22:10
  • @DavidHeffernan Way ahead of you :P – Jerry Dodge Feb 26 '12 at 22:37
  • Oh, so you've come to your senses then? ;-) – David Heffernan Feb 26 '12 at 22:37

5 Answers5

4

You can do something like this. Note that I've removed "abstract". It may work with "abstract" in place, but I haven't tried that.

type 
  TMyClass = class(TObject) 
  protected 
    procedure VProc; virtual; 
    procedure VAProc; virtual; //abstract;
  end; 


function GetVAProcAddress(Instance: TMyClass): pointer;
var
  p: procedure of object;
begin
  p := Instance.VAProc;
  result := TMethod(p).Code;
end;


//in one of the TMyClass methods you can now write:

  if GetVAProcAddress(self) <> @TMyClass.VAProc then
Giel
  • 2,066
  • 20
  • 22
  • 5
    This is a ridiculous amount of work - simply call the method. If it has no overridden behaviour to replace a base class defined no-op behaviour, then just allow the call to the no-op. This is almost certainly "cheaper" (and safer, should you need to introduce a base class implementation in the future that you DO want to be called) than jumping through hoops such as these. – Deltics Feb 27 '12 at 00:34
4

I think this is the wrong approach, it smells really really bad.. Some suggestions:

  • Use non-abstract methods that do what you want to do when they are not overridden.
  • Use events instead of methods. It's easy to check whether they have been assigned.
dummzeuch
  • 10,975
  • 4
  • 51
  • 158
  • Note 1 understood, Note 2 impossible because this is thread execution I'm talking about - certain reasons I can't use events. – Jerry Dodge Feb 26 '12 at 17:26
4

A method that may or may not be overridden is not an abstract method, it is merely virtual.

An abstract method is one that has no base implementation and for which an implementation must be provided by a descendant.

In your case, simply declare them as virtual and provide them with the NO-OP (No operation) default implementation that your design dictates:

type
  TMyBaseClass = class
    protected
      procedure SomeProc; virtual;
  end;


procedure TMyBaseClass.SomeProc;
begin
  // NO-OP
end;

Note - this illustrates my own personal convention of documenting a deliberate NO-OP, rather than just leaving an empty implementation.

Any shennanigans you go through to attempt to detect whether a declared abstract method has been overridden or not and to call it - or not - on the basis of that test is likely to cost more time than simply calling a NO-OP implementation. Plus, should you ever need to introduce an implementation in that base class you don't have to change the method from abstract to non-abstract (possibly disrupting those "detection" circuits you had w.r.t that method, and certainly rendering their cost as nothing but pure overhead).

Deltics
  • 22,162
  • 2
  • 42
  • 70
1

Use RTTI to get the method address of the virtual method in question for the class in questions. Compare it to the method address for the same method of the base class. If it is not the same, then the method was overriden.

Sean B. Durkin
  • 12,659
  • 1
  • 36
  • 65
  • 3
    Resist the temptation to indulge in exotic solutions to simple problems. Do what you need - implement virtual NON-abstract methods and just call them without worrying about whether they have been overridden or not. As you yourself said - overridden is fine, but so is NOT overridden, so why be concerned one way or the other ? The only time this becomes a problem is if the methods are (incorrectly) marked as abstract, which does not express your design in this case (abstract methods MUST be overridden, which is contrary to your stated need). – Deltics Feb 27 '12 at 00:36
1

If you got a line code like this:

lObj := TMyClass.Create;

you will notice that the compiler will output a warning saying that you are constructing instance of 'TMyClass' containing abstract method TMyClass.VAProc.

Henrick Hellström
  • 2,556
  • 16
  • 18
  • 3
    even better, configure the compiler to treat that as an error not a warning – David Heffernan Feb 26 '12 at 20:25
  • Can you do that in Delphi XE2? Either way, there is no need to mess with run time exceptions, since you already get abstract errors if you try to call abstract methods. If the goal is to detect such calls at compile time, the compiler already does that for you. – Henrick Hellström Feb 26 '12 at 21:34
  • You can do it in earlier versions too. Warnings can be configured to be either ignored, warnings or errors. Very handy. – David Heffernan Feb 26 '12 at 22:08