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:
declare the base TIdStack
methods as overload; virtual; abstract;
.
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;
overload
so any derived classes which overload it are introducing a change to the method signature and are 'hiding' the ancestor's definition. MarkaMethod
asoverload;virtual;abstract;
inTBaseClass
and the compiler warning goes away (even ifTBaseClass
does not define any overloaded variants). – J...