Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Method '%s' hides virtual method of base type '%s'". What's really being hidden?

After having read Ian Boyd's constructor series questions (1, 2, 3, 4), I realize I don't quite grasp the literal meaning on what's being hidden.

I know (correct me if I'm wrong) override's sole purpose is to be able to have polymorphic behavior, so that run-time can resolve a method depending on the actual type of an instance - as opposed to the declared type. Consider the following code:

type
  TBase = class
    procedure Proc1; virtual;
    procedure Proc2; virtual;
  end;

  TChild = class(TBase)
    procedure Proc1; override;
    procedure Proc2;            // <- [DCC Warning]
  end;

procedure TBase.Proc1;
begin
  Writeln('Base.Proc1');
end;
procedure TBase.Proc2;
begin
  Writeln('Base.Proc2');
end;

procedure TChild.Proc1;
begin
  inherited Proc1;
  Writeln('Child.Proc1');
end;
procedure TChild.Proc2;
begin
  inherited Proc2;
  Writeln('Child.Proc2');
end;

var
  Base: TBase;
begin
  Base := TChild.Create;
  Base.Proc1;
  Writeln;
  Base.Proc2;
  Base.Free;
  Readln;
end.

Which outputs:

Base.Proc1
Child.Proc1

Base.Proc2

The warning on TChild.Proc2 states that this method "will hide access to the base's method of the same name". What I see is, if I don't override Proc2 I loose the ability of the method's resolving to its actual type, not of its base type. How's that hiding access to base's method?

Further, down the documentation on the warning as a solution to the warning, it is stated that:

First, you could specify override to make the derived class' procedure also virtual, and thus allowing inherited calls to still reference the original procedure.

Now, if I create a 'TChild' instance from a 'TChild' (no polymorphism), the inherited call in the non-overridden method clearly refers to the original procedure. If I create the 'Child' instance from a 'TBase', the call does not even resolve to a 'TChild' method, how could I call 'Inherited' that would refer to anything at all?

What am I misunderstanding?

like image 941
Sertac Akyuz Avatar asked Oct 07 '10 04:10

Sertac Akyuz


3 Answers

Amongs other thing, you won't be able to define

TGrandChild = class(TChild) 
  procedure Proc2; override;
end; 

because Proc2 that TGrandChild sees is the one from TChild that is not virtual. The TChild.Proc2 hide TBase.Proc2 from descendants.

EDIT:

In answer to Sertac's comment:

var 
  Base: TBase; 
  Child : TChild
begin 
  Child := TChild.Create;
  Base := Child;
  Base.Proc2; 
  Child.Proc2;

  Base.Free; 
  Readln; 

That will output

Base.Proc2
Base.Proc2
Child.Proc2

So, what seems to be a call to the same method twice is actually a call to 2 different methods. That makes code harder to understand (which is not practical) and yield unexpected behavior.

like image 109
Ken Bourassa Avatar answered Nov 07 '22 06:11

Ken Bourassa


You are thinking too complicated. Hiding doesn't mean you completely lose access to the original. It simply means (and you already noted this yourself) if you have an object of static type TChild, and you call Proc2 on it, it calls the one in TChild, and not the one in TBase. Also what Ken said is true.

It is warning you because the original is virtual and hiding is most likely not what people intend when writing code like that. At the very least it's bad coding style.

like image 30
Timo Avatar answered Nov 07 '22 06:11

Timo


Use 'reintroduce' to suppress the warning.

like image 2
dwrbudr Avatar answered Nov 07 '22 07:11

dwrbudr