Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi Tdictionary inheritance

I try to inherit from Tdictionary and somehow the default comparer is lost. This is what I do in essence:

type
  TinpVar = class
  end;
  TinputVars = class(Tdictionary<string,TinpVar>)
  end;
  TLVRvars = class(TinputVars)
    constructor create;
  end;

 constructor TLVRvars.create;
 begin
   inherited;
 end;

 var LVRvars : TLVRvars;

 begin
   LVRvars:=TLVRvars.create;

With this construction I get an AV when adding a key/value pair to LVRvars. Eventually I found that this can be prevented by changing the constructor of the inherited class to

constructor TLVRvars.create;
begin
  inherited create;
end;

I do not understand why I have to do that. Although my problem is solved, I would still like to know.

like image 682
user3212191 Avatar asked Nov 08 '16 17:11

user3212191


1 Answers

In your constructor

 inherited;

calls the constructor with identical parameter list to your constructor. Your constructor has no parameters, and so inherited calls the do nothing constructor in TObject. Not only have you lost your comparer, but your instance is missing the rest of the necessary steps in construction.

When you replace it with

inherited Create;

the compiler instead performs normal method resolution. It looks up the class ancestor list and calls the first method which it can. In that case this is:

constructor Create(ACapacity: Integer = 0); overload;

Hence your instance is properly created.

The documentation is here: http://docwiki.embarcadero.com/RADStudio/en/Methods#Inherited

Key excerpts are:

If inherited is followed by the name of a member, it represents a normal method call

and

When inherited has no identifier after it, it refers to the inherited method with the same name as the enclosing method or, if the enclosing method is a message handler, to the inherited message handler for the same message. In this case, inherited takes no explicit parameters, but passes to the inherited method the same parameters with which the enclosing method was called. For example:

inherited;

occurs frequently in the implementation of constructors. It calls the inherited constructor with the same parameters that were passed to the descendant.

It's pretty weird isn't it. On the face of it, it seems astonishing that different methods are called. The key point though is that plain inherited leads to exact matching of parameter lists. And your method has no parameters.

On the other hand inherited Create is a standard method call. In that latter case, you end up calling a method with one parameter, using the default value for that parameter. So whilst it looks like you are calling a parameterless constructor you are not. You are passing one parameter, ACapacity, and a value of 0.

like image 83
David Heffernan Avatar answered Nov 07 '22 13:11

David Heffernan