Abstract error when changing TStringList to TStrings - delphi

Ok this is becoming quite silly...
It's the second time (the first time was 30min before, on a function to get directory tree) I ever see the error "Abstract error", and really can't tell why would it happen.
I had this function, to list all of the hard drives:
function TForm2.GetDriveList:TStringList;
var
s:string;
i:integer;
DriveStr:array[1..255] of char;
t:integer;
begin
GetLogicalDriveStrings(255,#DriveStr);
result:=TStringList.create;
i:=1;
repeat
s:='';
while (i<=255) and (DriveStr[i]<>#00) do
begin
s:=s+char(drivestr[i]);
inc(i);
end;
inc(i); {step over #00}
t:=getdrivetype(Pchar(s));
if (length(s)>0) and (t=DRIVE_FIXED)
then result.add(s);
until length(s)=0;
end;
Now, I changed the TStringList to TStrings, and I get this Abstract error when trying to call it;
I also tried to change it to procedure, as
procedure TFrom2.GetDriveList(List: TStrings);
removing the result from the code, and having List.Add(s) at the end;
This (function to procedure) somehow solved the issue in my first case, but doesn't on this one.
My questions are:
What is wrong in the code above, and why is TStrings not accepted...?
and: what the heck are these abstract errors, how to identify them, since they appear (by debug inspection) on the very end of the function/procedure, after it is basically already done?

TStrings is an abstract base class. It must not be instantiated. It exists to be a common base class for concrete derived classes. Like TStringList for one, like the TStrings derived classes exposed by TMemo, TListBox and so on. The documentation says:
TStrings is the base class for objects that represent a list of strings.
Derive a class from TStrings to store and manipulate a list of strings. TStrings contains abstract or, in C++ terminology, pure virtual methods and should not be directly instantiated.
The rule is stated clearly. Do not instantiate TStrings.
An abstract error is the runtime error that arises when you call an abstract method. An abstract method is a virtual method that has no implementation. Abstract methods cannot be called. This is why abstract classes should not be instantiated.
If you are not familiar with what an abstract method is then you need to go back to the documentation and brush up your knowledge. Start here: http://docwiki.embarcadero.com/RADStudio/en/Methods#Virtual_and_Dynamic_Methods

Related

FreePascal RTTI. Is there a way to invoke method?

I'm trying to find out if there is a way to do things similar to Delphi's enhanced RTTI features.
As far as I know FPC doesn't provide RTTI features which appeared in Delphi since Delphi 2010. But I'd like to find some way to do a few tricks during runtime.
Using typinfo unit in FPC I can do such things as:
get Object published property list - via getPropList from typinfo unit;
get/set value of the Object's published property - via GetPropValue(...): Variant/SetPropValue(...Value: Variant);
get published method - via MethodAddres;
But I haven't found a way to do things like:
call methods;
call constructors, or create Objects;
Update: the problem with constructors is much like methods one - I want to have a way to pass different params in it:
// concept of code
type
TClass = class of TObject;
TMyClass1 = class
public
constructor Create(Param1: Integer; Param2: string); override;
end;
TMyClass2 = class
public
constructor Create(ObjectParam: Object); override;
end;
TParams = array of Variant;
var
Classes: array of TClass
Instances: array of Object;
ParamArray: array of TParams;
...
For I := 0 to Count-1 do
begin
LocalConstructor := #(Classes[I].Create);
Instances[I] := CallConstructor(LocalConstructor, ParamArray[I]);
end;
So I need to call constructor without knowing its signature.
So my problem is to call an Object's method and pass some parameters to it. It could look like function CallMethod(Instance: Object; MethodName: String; Params: array of Variant): Variant;
If I'm not mistaken it could be solved via Delphi's 2010+ RTTI. But before using enhanced Delphi's RTTI I'd like to understand is it possible in FPC.
In other words my current problem is pass arguments to a routine.
I know it can be done using this scheme:
type
TmyProc = procedure CallMe(x: byte);
...
var proc: TmyProc;
...
proc := pointerToFunc^;
proc(0);
But I need to implement it without knowing count and types of parameters (during compile time).
There are a few links related to the topic:
Delphi: Call a function whose name is stored in a string
http://www.swissdelphicenter.ch/torry/showcode.php?id=1745
The second article (http://www.swissdelphicenter.ch/torry/showcode.php?id=1745) describes a way to pass arguments to a routine imported from DLL by name. Which is almost that I need I suppose. But I'm not sure that way is reliable.
Maybe there's any library, which implements these things using "old" typinfo unit (without RTTI unit)?
Also I'm interested in a way to create some kind of universal event handlers - procedures which can be assigned to different events (with different sets of parameters) e.g.:
procedure myEventHandler(params: array of variant);
...
Button.OnClick := myEventHandler;
Button.OnMouseMove := myEventHandler;
is this possible? Or at least something similar to it?
You can call methods, even not published, using MethodAddress, but it's up to you to ensure correct argument list.
You can call constructors using metaclasses (class references), example of it could be seen in TCollection: you pass class of your collection item at runtime and then it can be created when needed. By defining abstract class with virtual (and probably abstract) constructor, you can come up with argument list you wish, some example here.
AFAIK there is no way to determine argument list at runtime, but if you design both the methods to call and caller itself, there are many ways you can implement similar behavior.
For example, you pass variant open array (Array of const), as it's done in Format(), so number of arguments and its type may vary. But even having one and only pointer as the argument, you sure can pass as many as you want, all you need to do is to come up with some class to which it will lead.

Why is using procedures to create objects preferred over functions?

This is similar to this question. I asked "Why?" to the most popular response but I don't know that anyone would ever look at it again. At least not in any timely manner.
Anyway, my question is about best practices for delegating responsibility for creation of objects to functions or procedures, without causing memory leaks. It seems that this:
procedure FillObject(MyObject: TMyObject; SomeParam: Integer);
begin
//Database operations to fill object
end;
procedure CallUsingProcedure();
var
MyObject: TMyObject;
begin
MyObject = TMyObject.Create();
try
FillObject(MyObject, 1);
//use object
finally
MyObject.Free();
end;
end;
is preferred over this:
function CreateMyObject(DBID: Integer): TMyObject;
begin
Result := TMyObject.Create();
try
//Database operations to fill object
except on E: Exception do
begin
Result.Free();
raise;
end;
end;
end;
procedure CallUsingFunction();
var
MyObject: TMyObject;
begin
MyObject = CreateMyObject(1);
try
//use object
finally
MyObject.Free();
end;
end;
Why?
I'm relatively new to Delphi, having previously worked most with Java and PHP, as well as C++, though to a lesser extent. Intuitively, I lean toward the function method because:
It encapsulates the object creation code in the function, rather than create the object separately whenever I want to use the procedure.
I dislike methods that alter their parameters. It's often left undocumented and can make tracing bugs more difficult.
Vague, but admittedly it just "smells" bad to me.
I'm not saying I'm right. I just want to understand why the community chooses this method and if there is good reason for me to change.
Edit:
References to #E-Rock in comments are to me(Eric G). I changed my display name.
One problem is what Ken White wrote: you hand the user of the function an object he or she must free.
Another advantage of procedures is that you can pass several objects of a hierarchy, while a function that creates such an object always generates the same. E.g.
procedure PopulateStrings(Strings: TStrings);
To that procedure, you can pass any kind of TStrings, be it the Lines of a TMemo, the Items of a TListBox or TComboBox or a simple standalone TStringList. If you have a function:
function CreateStrings: TStrings;
You always get the same kind of object back (which object exactly is not known, as TStrings is abstract, so you probably get a TStringList), and must Assign() the contents to the TStrings you want to modify. The procedure is to be preferred, IMO.
Additionally, if you are the author of the function, you can't control whether the object you create is freed, or when. If you write a procedure, that problem is taken off your hands, since the user provides the object, and its lifetime is none of your concern. And you don't have to know the exact type of the object, it must just be of the class or a descendant of the parameter. IOW, it is also much better for the author of the function.
It is IMO seldom a good idea to return an object from a function, for all the reasons given. A procedure that only modifies the object has no dependency on the object and creates no dependency for the user.
FWIW, Another problem is if you do that from a DLL. The object returned uses the memory manager of the DLL, and also the VMT to which it points is in the DLL. That means that code that uses as or is in the user code does not work properly (since is and as use the VMT pointer to check for class identity). If the user must pass an object of his, to a procedure, that problem does not arise.
Update
As others commented, passing an object to a DLL is not a good idea either. Non-virtual functions will call the functions inside the DLL and use its memory manager, which can cause troubles too. And is and as will not work properly inside the DLL either. So simply don't pass objects into or out of a DLL. That goes with the maxime that DLLs should only use POD type parameters (or compound types -- arrays, records -- that only contain POD types) or COM interfaces. The COM interfaces should also only use the same kind of parameters.
Creating the object instance and passing it into another procedure makes it clear which code is responsible for freeing the instance.
In the first case (using a procedure to fill it):
MyObj := TMyObject.Create;
try
// Do whatever with MyObj
finally
MyObj.Free;
end;
This is clear that this block of code is responsible for freeing MyObj when it's finished being used.
MyObj := CreateMyObject(DBID);
What code is supposed to free it? When can you safely free it? Who is responsible for exception handling? How do you know (as a user of someone else's code)?
As a general rule, you should create, use, and free object instances where they're needed. This makes your code easier to maintain, and definitely makes it easier for someone who comes along later and has to try and figure it out. :)
I use a combination of both idioms. Pass the object as an optional parameter and if not passed, create the object. And in either case return the object as the function result.
This technique has (1) the flexibility of the creation of the object inside of the called function, and (2) the caller control of the caller passing the object as a parameter. Control in two meanings: control in the real type of the object being used, and control about the moment when to free the object.
This simple piece of code exemplifies this idiom.
function MakeList(aList:TStrings = nil):TStrings;
var s:TStrings;
begin
s:=aList;
if s=nil then
s:=TSTringList.Create;
s.Add('Adam');
s.Add('Eva');
result:=s;
end;
And here are three different ways to use it
simplest usage, for quick and dirty code
var sl1,sl2,sl3:TStrings;
sl1:=MakeList;
when programmer wants to make more explicit ownership and/or use a custom type
sl2:=MakeList(TMyStringsList.create);
when the object is previously created
sl3:=TMyStringList.Create;
....
MakeList(sl3);

Correct way to duplicate Delphi object

What are pros and cons of duplication an object instance with constructor or instance function?
Example A:
type
TMyObject = class
strict private
FField: integer;
public
constructor Create(srcObj: TMyObject); overload;
//alternatively:
//constructor CreateFrom(srcObj: TMyObject);
property Field: integer read FField;
end;
constructor TMyObject.Create(srcObj: TMyObject);
begin
inherited Create;
FField := srcObj.Field;
end;
Example B:
type
TMyObject = class
strict private
FField: integer;
public
function Clone: TMyObject;
property Field: integer read FField;
end;
function TMyObject.Clone: TMyObject;
begin
Result := TMyObject.Create;
Result.FField := FField;
end;
One major difference immediately springs to mind - in the latter case the Create constructor would have to be virtual so that a class hierarchy supporting Clone could be built basing on the TMyObject.
Assume that this is not a problem - that TMyObject and everything based on it is entirely under my control. What is your preferred way of doing copy constructor in Delphi? Which version do you find more readable? When would you use former or latter approach? Discuss. :)
EDIT:
My main concern with the first example is that the usage is very heavy compared to the second approach, i.e.
newObj := TMyObject.Create(oldObj)
vs.
newObj := oldObj.Clone;
EDIT2 or "Why I want single-line operation"
I agree that Assign is a reasonable approach in most cases. It's even reasonable to implement 'copy constructor' internally by simply using assign.
I'm usually creating such copies when multithreading and passing objects through the message queue. If object creation is fast, I usually pass a copy of the original object because that really simplifies the issues of object ownership.
IOW, I prefer to write
Send(TMyObject.Create(obj));
or
Send(obj.Clone);
to
newObj := TMyObject.Create;
newObj.Assign(obj);
Send(newObj);
The first adds information about which object to want to create, the second not. This can be used to instantiate e.g. a descendant or an ancestor of a class
The Delphi way (TPersistent) separates creation and cloning:
dest := TSomeClass.Create;
dest.Assign(source);
and has this same property that you explicitly choose the class to instantiate. But you don't need two constructors, one for normal use, and one where you want to clone.
edit due to oneline requirement
You can mix it of course using Delphi metaclasses (untested)
type
TBaseSomeObject = class;
TBaseObjectClass = class of TBaseSomeObject;
TBaseSomeObject = class(TPersistent)
function Clone(t: TBaseObjectClass = nil): TBaseSomeObject; virtual;
end;
...
function TBaseSomeObject.Clone(t: TBaseObjectClass = nil): TBaseSomeObject;
begin
if Assigned(t) then
Result := t.Create
else
Result := TBaseObjectClass(Self.ClassType).Create;
Result.Assign(Self);
end;
SendObject(obj.Clone); // full clone.
SendObject(obj.Clone(TDescandantObject)); // Cloned into Descendant object
For the rest, just implement your assign() operators, and you can mix multiple ways.
edit2
I replaced the code above with code tested in D2009. There are some dependencies of the types that might have confused you, hope it is clearer this way. Of course you'll have to study the assign mechanism. I also tested the metaclass=nil default parameter and it works, so I added it.
I don't think there is a correct way it just depend on personal style. (And as Marco pointed out, there are more ways.)
The constructor way is short but it violates the principle that the constructor must only construct the object. Which is possibly not a problem.
The clone way is short although you need to provide a call for each class.
The assign way is more Delphi like. It separates creation and initialization which is good because we like the one method one function concept that makes code better to maintain.
And if you implement Assign using streams, you have only one place to worry about which fields need to be available.
I like the clone style - but only in Java (or any other GC language). I used it some times in Delphi, but mostly I stay with Create and Assign, because it is much clearer who is responsible for the destruction of the object.
I use the second method, the one with the Clone function, and it works like a charm, even with complex classes. I find it more readable and error proof.

How to design constructors in a hierarchy where there are just readonly fields without having too many parameters?

I have designed a hierarchy, every class has 2 readonly properties mapped to 2 private fields.
Every class has a cosntructor that inherits the parent class one.
The problem is that at every level of hierarchy the number of parameters increase of 2:
TBaseClass.Create (par1, par2);
TSubClass.Create(par1, par2, par3, par4);
TSubSubClass.Create(par1, par2, par3, par4, par5, par6);
[...]
Is it ok to have constructors with 6-8 parameteres? After creation my objects should be immutable, so this is why I try to initialize all fileds in the constructors.
Is there another technique you can suggest or should I go with the above mentioned approach? Thanks.
As long as they're well-documented, I've never had any stigma against functions with large numbers of parameters. So an 8-param constructor wouldn't scare me.
However, I can see where the explosion-of-params could occur here, especially if you start adding more than 2 properties per object. I could also see an uncomfortable proliferation of constructor overloads, if some of those params can be defaulted/optional.
With that in mind, you might want to encapsulate the complexities of setting all those params, by using a construction pattern. Builder comes to mind, though Factory or Prototype might also be useful.
Best to stick with conventions when you can. A Builder implies a sequential or multiple object creation process. Abstract Factory is more appropriate for creating a single object from a hierarchy.
Having said that, the regularity does seem a little odd. Does SubClass3 in fact need all 6 properties or only it's two? Remember LSP - SubClass3 is supposed to be completely substitutible for BaseClass so at each level the new ancestor assumes responsibility for the entire set, which is usually more than just passing them back through constructors.
Why don't you let those properties be writable and protect the object by casting it to an interface? Like this:
type
IMyObject = interface
function GetProperty1(): integer;
function GetProperty2(): boolean;
end;
TMyObject = class(TInterfacedObject, IMyObject)
public
constructor Create();
function GetProperty1(): integer;
function GetProperty2(): boolean;
procedure SetProperty1(Value: integer);
procedure SetProperty2(Value: boolean);
end;
function CreateMyObject: IMyObject;
var obj: TMyObject
begin
obj := TMyObject.Create;
obj.SetProperty1(45);
obj.SetProperty2(false);
Result := obj;
end;

Reintroducing functions in Delphi

What was the motivation for having the reintroduce keyword in Delphi?
If you have a child class that contains a function with the same name as a virtual function in the parent class and it is not declared with the override modifier then it is a compile error. Adding the reintroduce modifier in such situations fixes the error, but I have never grasped the reasoning for the compile error.
If you declare a method in a descendant class that has the same name as a method in an ancestor class then you are hiding that ancestor method — meaning if you have an instance of that descendant class (that is referenced as that class) then you will not get the behavior of the ancestor. When the ancestor's method is virtual or dynamic, the compiler will give you a warning.
Now you have one of two choices to suppress that warning message:
Adding the keyword reintroduce just tells the compiler you know you are hiding that method and it suppresses the warning. You can still use the inherited keyword within your implementation of that descended method to call the ancestor method.
If the ancestor's method was virtual or dynamic then you can use override. It has the added behavior that if this descendant object is accessed through an expression of the ancestor type, then the call to that method will still be to the descendant method (which then may optionally call the ancestor through inherited).
So difference between override and reintroduce is in polymorphism. With reintroduce, if you cast the descendant object as the parent type, then call that method you will get the ancestor method, but if you access it the descendant type then you will get the behavior of the descendant. With override you always get the descendant. If the ancestor method was neither virtual nor dynamic, then reintroduce does not apply because that behavior is implicit. (Actually you could use a class helper, but we won't go there now.)
In spite of what Malach said, you can still call inherited in a reintroduced method, even if the parent was neither virtual nor dynamic.
Essentially reintroduce is just like override, but it works with non-dynamic and non-virtual methods, and it does not replace the behavior if the object instance is accessed via an expression of the ancestor type.
Further Explanation:
Reintroduce is a way of communicating intent to the compiler that you did not make an error. We override a method in an ancestor with the override keyword, but it requires that the ancestor method be virtual or dynamic, and that you want the behavior to change when the object is accessed as the ancestor class. Now enter reintroduce. It lets you tell the compiler that you did not accidentally create a method with the same name as a virtual or dynamic ancestor method (which would be annoying if the compiler didn't warn you about).
There are lots of answers here about why a compiler that lets you hide a member function silently is a bad idea. But no modern compiler silently hides member functions. Even in C++, where it's allowed to do so, there's always a warning about it, and that ought to be enough.
So why require "reintroduce"? The main reason is that this is the sort of bug that can actually appear by accident, when you're not looking at compiler warnings anymore. For example, let's say you're inheriting from TComponent, and the Delphi designers add a new virtual function to TComponent. The bad news is your derived component, which you wrote five years ago and distributed to others, already has a function with that name.
If the compiler just accepted that situation, some end user might recompile your component, ignore the warning. Strange things would happen, and you would get blamed. This requires them to explicitly accept that the function is not the same function.
The RTL uses reintroduce to hide inherited constructors. For example, TComponent has a constructor which takes one argument. But, TObject has a parameterless constructor. The RTL would like you to use only TComponent's one-argument constructor, and not the parameterless constructor inherited from TObject when instantiating a new TComponent. So it uses reintroduce to hide the inherited constructor. In this way, reintroduce is a little bit like declaring a parameterless constructor as private in C#.
First of all, "reintroduce" breaks the inheritance chain and should not be used, and I mean never ever. In my entire time I worked with Delphi (ca 10 years) I've stumbled upon a number of places that do use this keyword and it has always been a mistake in the design.
With that in mind here's the simplest way it works:
You have like a virtual method in a base class
Now you wanna have a method that has the exact same name, but maybe a different signature. So you write your method in the derived class with the same name and it will not compile because the contract is not fulfilled.
You put the reintroduce keyword in there and your base class does not know about your brand new implementation and you can use it only when accessing your object from a directly specified instance type. What that means is toy can't just assign the object to a variable of base type and call that method because it's not there with the broken contract.
Like I said it's pure evil and must be avoided at all cost (well, that's my opinion at least). It's like using goto - just a terrible style :D
The purpose of the reintroduce modifier is to prevent against a common logical error.
I will assume that it is common knowledge how the reintroduce keyword fixes the warning and will explain why the warning is generated and why the keyword is included in the language. Consider the delphi code below;
TParent = Class
Public
Procedure Procedure1(I : Integer); Virtual;
Procedure Procedure2(I : Integer);
Procedure Procedure3(I : Integer); Virtual;
End;
TChild = Class(TParent)
Public
Procedure Procedure1(I : Integer);
Procedure Procedure2(I : Integer);
Procedure Procedure3(I : Integer); Override;
Procedure Setup(I : Integer);
End;
procedure TParent.Procedure1(I: Integer);
begin
WriteLn('TParent.Procedure1');
end;
procedure TParent.Procedure2(I: Integer);
begin
WriteLn('TParent.Procedure2');
end;
procedure TChild.Procedure1(I: Integer);
begin
WriteLn('TChild.Procedure1');
end;
procedure TChild.Procedure2(I: Integer);
begin
WriteLn('TChild.Procedure2');
end;
procedure TChild.Setup(I : Integer);
begin
WriteLn('TChild.Setup');
end;
Procedure Test;
Var
Child : TChild;
Parent : TParent;
Begin
Child := TChild.Create;
Child.Procedure1(1); // outputs TChild.Procedure1
Child.Procedure2(1); // outputs TChild.Procedure2
Parent := Child;
Parent.Procedure1(1); // outputs TParent.Procedure1
Parent.Procedure2(1); // outputs TParent.Procedure2
End;
Given the above code both of the procedures in TParent are hidden. To say they are hidden means that the procedures can not be called through the TChild pointer. Compiling the code sample produces a single warning;
[DCC Warning] Project9.dpr(19): W1010 Method 'Procedure1' hides virtual method of base type 'TParent'
Why only a warning for the virtual function and not the other? Both are hidden.
A virtue of Delphi is that library designers are able to release new versions without fear of breaking the logic of existing client code. This contrasts to Java where adding new functions to a parent class in a library is fraught with danger because classes are implicitly virtual. Lets say that TParent from above lives in a 3rd party library, and the library manufacture releases the new version below.
// version 2.0
TParent = Class
Public
Procedure Procedure1(I : Integer); Virtual;
Procedure Procedure2(I : Integer);
Procedure Procedure3(I : Integer); Virtual;
Procedure Setup(I : Integer); Virtual;
End;
procedure TParent.Setup(I: Integer);
begin
// important code
end;
Imagine we had the following code in our client code
Procedure TestClient;
Var
Child : TChild;
Begin
Child := TChild.Create;
Child.Setup;
End;
For the client it does not matter if the code is compiled against version 2 or 1 of the library, in both cases TChild.Setup is called as the user intends. And in the library;
// library version 2.0
Procedure TestLibrary(Parent : TParent);
Begin
Parent.Setup;
End;
If TestLibrary is called with a TChild parameter, everything works as intended. The library designer have no knowledge of the TChild.Setup, and in Delphi this does not cause them any harm. The call above correctly resolves to TParent.Setup.
What would happen in a equivalent situation in Java? TestClient would work correctly as intended. TestLibrary would not. In Java all functions are assumed virtual. The Parent.Setup would resolve to TChild.Setup, but remember when TChild.Setup was written they had no knowledge of the future TParent.Setup, so they are certainly not going to ever call inherited. So if the library designer intended TParent.Setup to be called it will not be, no matter what they do. And certainly this could be catasrophic.
So the object model in Delphi requires explicit declaration of virtual functions down the chain of child classes. A side effect of this is that it is easy to forget to add the override modifier on child methods. The existence of the Reintroduce keyword is a convenience to the programmer. Delphi was designed so that the programmer is gently persuaded, by the generation of a warning, to explicitly state their intentions in such situations.
tl;dr: Trying to override a non-virtual method makes no sense. Add the keyword reintroduce to acknowledge that you're making a mistake.
Reintroduce tells the compiler you want to call the code defined in this method as an entry point for this class and its descendants, regardless of other methods with the same name in the ancestors’ chain.
Creating a TDescendant.MyMethod would create a potential confusion for the TDescendants in adding another method with the same name, which the compiler warns you about.
Reintroduce disambiguates that and tells the compiler you know which one to use.
ADescendant.MyMethod calls the TDescendant one, (ADescendant as TAncestor).MyMethod calls the TAncestor one. Always! No confusion…. Compiler happy!
This is true whether you want the descendant method to be virtual or not: in both cases you want to break the natural linkage of the virtual chain.
And it does not prevent you from calling the inherited code from within the new method.
TDescendant.MyMethod is virtual: ...but you cannot or don’t want to use the linkage.
You cannot because the method signature is different. You have no other choice as overriding is impossible in this case with return type or parameters not exactly the same.
You want to restart an inheritance tree from this class.
TDescendant.MyMethod is not virtual: You turn MyMethod into a static one at the TDescendant level and prevent further overriding. All classes inheriting from TDescendant will use the TDescendant implementation.
When the ancestor class also has a method with the same name, and it is not necessarily declared virtual, you would see a compiler warning (as you would hide this method).
In other words: You tell the compiler that you know that you hide the ancestor function and replace it with this new function and do so deliberately.
And why would you do this? If the method is virtual in the parent class, the only reason is to prevent polymorphism. Other then that just override and do not call inherited. But if the parent method is not declared virtual (and you cannot change that, because you do not own the code for example), you can inherit from that class and let people inherit from your class without seeing a compiler warning.
This has been introduced to the language because of Framework versions (including the VCL).
If you have an existing code base, and an update to a Framework (for instance because you bought a newer Delphi version) introduced a virtual method with the same name as a method in an ancestor of your code base, then reintroduce will allow you to get rid of the W1010 warning.
This is the only place where you should use reintroduce.
First, as it was said above, you should never ever deliberately reintroduce virtual method. The only sane use of reintroduce is when the author of the ancestor (not you) added a method that goes into conflict with your descendant and renaming your descendant method is not an option. Second, you can easily call the original version of the virtual method even in classes where you reintroduced it with different parameters:
type
tMyFooClass = class of tMyFoo;
tMyFoo = class
constructor Create; virtual;
end;
tMyFooDescendant = class(tMyFoo)
constructor Create(a: Integer); reintroduce;
end;
procedure .......
var
tmp: tMyFooClass;
begin
// Create tMyFooDescendant instance one way
tmp := tMyFooDescendant;
with tmp.Create do // please note no a: integer argument needed here
try
{ do something }
finally
free;
end;
// Create tMyFooDescendant instance the other way
with tMyFooDescendant.Create(20) do // a: integer argument IS needed here
try
{ do something }
finally
free;
end;
so what should be the purpose of reintroducing virtual method other than make things harder to read?
reintroduce allows you to declare a method with the same name as the ancestor, but with different parameters. It has nothing to do with bugs or mistakes!!!
For example, I often use it for constructors...
constructor Create (AOwner : TComponent; AParent : TComponent); reintroduce;
This allows me to create the internal classes in a cleaner fashion for complex controls such as toolbars or calendars. I normally have more parameters than that. Sometimes it is almost impossible or very messy to create a class without passing some parameters.
For visual controls, Application.Processmessages can get called after Create, which can be too late to use these parameters.
constructor TClassname.Create (AOwner : TComponent; AParent : TComponent);
begin
inherited Create (AOwner);
Parent := AParent;
..
end;

Resources