Why does the compiler warn when overloading an abstract method introduced in the base class?

I have code like this:

TBaseClass = class(TObject)
protected
  procedure aMethod(const s:string);virtual;abstract;
end; 

TDerivedClass = class(TBaseClass)
protected
   procedure aMethod(const s:string);overload;override;
   procedure aMethod(const s:string;const x:integer);overload;
end; 

Compiler generates a warning:

[DCC Warning].... W1010 Method 'aMethod' hides virtual method of base type 'TBaseClass'

Clicking on the warning sends me to 'aMethod(const s:string;const x:integer);' since it is not marked with the override directive. However that method CANNOT be marked override: no method with that signature exists in the base class, and adding the override directive to that method causes a compiler error :

[DCC Error].... E2037 Declaration of 'aMethod' differs from previous declaration.

This is obvious, since no method with that signature exists in TBaseClass.

Only 'aMethod(const s:string)' exists in the base class and that method is marked 'override' - so nothing in the base class is being hidden at all.

Why is this not an erroneous warning? (not the first one I've come across, either..)

The reference to the other question is incorrect, IMO. I have a solution - I simply used refactor, and renamed the problematic method. But I'm not looking for a solution, which is trivial. I'm looking for an explanation of this warning. Is there something wrong with this design? (Perhaps using overload and override together is not good design - I can agree with that, but that's not what the compiler warning is really about)

Answers


I recently ran into this same problem in Indy. Its TIdStack base class has abstract GetSocketOption() and SetSocketOption() methods that TIdStackBDSBase would override and overload with its own abstract methods for its descendants (TIdStackWindows, etc) to override. I was getting these exactly same kinds of compiler errors.

For example:

type
  TIdStack = class(TObject)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle;
      ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption;
      out AOptVal: Integer); virtual; abstract;
    ...
  end;

.

type
  TIdStackBSDBase = class(TIdStack)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
      AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
      AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); overload; virtual; abstract;
    ...
  end;

procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle;
  ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
var
  LBuf, LLen: Integer;
begin
  LLen := SizeOf(LBuf);
  GetSocketOption(ASocket, ALevel, AOptName, LBuf, LLen);
  AOptVal := LBuf;
end;

.

type
  TIdStackWindows = class(TIdStackBSDBase)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel;
      AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
    ...
  end;

procedure TIdStackWindows.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
begin
  ...
end;

Regardless of whether TIdStack.GetSocketOption() is declared as overload or not, XE2 reports this error:

[DCC Error] IdStackWindows.pas(296): E2137 Method 'GetSocketOption' not found in base class

It turns out that in some situations (like Indy's), the compiler requires the base class method to be declared as overload (even if there is no corresponding overloaded method in the base class itself) in order for a derived class to override + overload it.

However, when I did that, it did not work in XE2 and earlier, causing the "hides virtual method" warnings and other errors. That appears to have been fixed in XE3. So what I ended up having to do in Indy was:

  1. declare the base TIdStack methods as overload; virtual; abstract;.

  2. in TIdStackBDSBase, declare the overriden methods as overload; override;, then:

    a. in XE2 and earlier, declare the overloaded methods as reintroduce; overload;, and declare separate non-overloaded virtual; abstract; methods for descendants to override.

    b. in XE3 and later, declare the overloaded methods as overload; virtual; abstract;, and let descendants override them normally.

In other words, the following code works in XE3 but not in XE2:

type
  TIdStack = class(TObject)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; virtual; abstract;
    ...
  end;

.

type
  TIdStackBSDBase = class(TIdStack)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); overload; virtual; abstract;
    ...
  end;

  procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
  var
    LBuf, LLen: Integer;
  begin
    LLen := SizeOf(LBuf);
    GetSocketOption(ASocket, ALevel, AOptName, LBuf, LLen);
    AOptVal := LBuf;
  end;

.

type
  TIdStackWindows = class(TIdStackBSDBase)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
    ...
  end;

  procedure TIdStackWindows.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
  begin
    ...
  end;

The following code works in XE2, though:

type
  TIdStack = class(TObject)
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; virtual; abstract;
    ...
  end;

.

type
  TIdStackBSDBase = class(TIdStack)
    ...
    procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); virtual; abstract;
    ...
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; override;
    procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); reintroduce; overload;
    ...
  end;

procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer);
var
  LBuf, LLen: Integer;
begin
  LLen := SizeOf(LBuf);
  WSGetSocketOption(ASocket, ALevel, AOptName, LBuf, LLen);
  AOptVal := LBuf;
end;

procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
begin
  WSGetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen);
end;

.

type
  TIdStackWindows = class(TIdStackBSDBase)
    ...
    procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); override;
    ...
  end;

  procedure TIdStackWindows.WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer);
  begin
    ...
  end;

Need Your Help

Understanding Mocha syntax in an 'integration' test

node.js testing mocha

I have a pretty extensive background with Ruby and Rspec. However, as I'm learning Node and Mocha, I've come across syntax that I can't seem to understand.

Function that takes a predicate function (returning a boolean), and returns a predicate function with the same parameters

generics typescript variadic

So, I want to create a negate function, that takes some function that returns a boolean for some list of arguments, and returns a function that takes the same arguments and produces the exact oppos...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.