Calling Virtual Function in FormCreate - delphi

I am playing with an already existing code. I have a base class form where i introduce a virtual function and calling the function in FormCreate. In some derived class i override the function and have my own implementation. But when i am executing the application i am getting "EAbstract error". I dont know why i am getting this exception. When i debugged it is FormCreate is executing well for some forms but for some other forms i am getting this exception. I am new to Delphi so ignore my ignorance. Thanks.

Somewhere in your program is a class which declares an abstract virtual:
procedure Foo; virtual; abstract;
And your program instantiates a class that does not override this abstract method, and then calls the method. When this method is called, an EAbstractError exception is raised.
The abstract method is not necessarily declared in code that you wrote. For example, perhaps you instantiated a TStrings class:
Strings := TStrings.Create;
when you meant to write
Strings := TStringList.Create;
Subsequent method calls on the TStrings instance will lead to abstract errors. Remember that TStrings is an abstract class full of abstract methods.
With many patterns of class instantiation your code would lead to a compiler warning. The compiler will warn that you are instantiating a class that contains abstract methods. If your mistake is as suggested above, then the compiler warnings will locate the error for you. I cannot stress enough the importance of listening to the compiler's warnings.
However, if the abstract class in question is a form, then the compiler will not be able to warn if you are using Application.CreateForm to instantiate it.
If your code declares the abstract method, then you can find the problem readily by performing a search (Find in Files) for the uses of abstract. If that does not help, and there are no compiler warnings, then configure the debugger to break on exceptions and then take a look at the call stack when the program breaks on the exception.

Related

Is there a way to dynamically type cast by class information parameter in Delphi?

I am having some difficulty understanding typecasting when using a class that is a passed parameter. I tried searching for this but couldn't find other answers.
I am working with some legacy Delphi code, using Delphi 2006, which doesn't support Generics (introduced in Delphi 2009).
The code is using TLists to store pointers to instantiated classes of particular types. When clearing the list, they use this:
procedure ClearList(AList: TList);
var i: Integer;
begin
for i := 0 to AList.Count - 1 do
TObject(AList[i]).Free;
AList.Clear;
end;
And it is called like this:
ClearList(FExtraVisitTypes);
ClearList(FDiagnoses);
ClearList(FProcedures);
ClearList(FImmunizations);
ClearList(FSkinTests);
ClearList(FPatientEds);
ClearList(FHealthFactors);
ClearList(FExams);
My understanding of this may be off, but I am concerned that if the pointed-to objects are freed as TObject, that the destructor of the descendant object won't be called, potentially leading to a memory leak. (My polymorphisim kung-fu is a bit rusty, which may be causing my confusion.)
So I tried to change the clear function as below:
procedure ClearList(AList: TList; ItemClass: TPCEItemClass); //mod to add ItemClass
var i: Integer;
begin
for i := 0 to AList.Count - 1 do begin
(AList[i] as ItemClass).Free;
end;
AList.Clear;
end;
TPCEItemClass is defined like this:
TPCEItemClass = class of TPCEItem;
I then changed the clear calls like this:
ClearList(FExtraVisitTypes, TPCEProc);
ClearList(FDiagnoses, TPCEDiag);
ClearList(FProcedures, TPCEProc);
ClearList(FImmunizations, TPCEImm);
ClearList(FSkinTests, TPCESkin);
ClearList(FPatientEds, TPCEPat);
ClearList(FHealthFactors, TPCEHealth);
ClearList(FExams, TPCEExams);
But the compiler won't allow this and gives this error:
[Pascal Error] uPCE.pas(1730): E2015 Operator not applicable to this operand type
For this erroneous line:
(AList[i] as ItemClass).Free;
Questions:
Does the original way of coding, where the item is freed by simply calling the great-great-great (etc) ancestor Free method end up effecting the descendant's destructor method? As I write this, I'm now thinking that it actually does. But I don't know why. So any answers to help me keep this in my head would be great.
Why does my method of trying to typecast via the parameter which is of type class not work? Is this just not allowed? Or is my syntax wrong? Is there another way to do this?
Am I going about this all wrong? Is there a better way?
Thanks
I am concerned that if the pointed-to objects are freed as TObject, that the destructor of the descendant object won't be called, potentially leading to a memory leak.
That is not the case for classes that are properly implemented.
All classes derive from TObject. TObject.Free() calls the TObject.Destroy() destructor, which is virtual. Any descendant that requires destruction logic must override that destructor (if it doesn't, it has a flaw that needs fixing).
So, in properly written code, the original code will work perfectly fine as shown. Calling Free() on any valid and correctly implemented object will invoke its most-derived destructor.
Now, that being said, there have been plenty of cases over the years of people forgetting to override the destructor when their classes require it, thus causing the kinds of memory leaks you are worried about. So, make sure you pay attention to what your classes are doing, and you will be fine.
So I tried to change the clear function as below ... But the compiler won't allow this and gives this error
Correct, because you can't perform a type-cast on an object using a variable to a metaclass type, like you are trying to do. Type-casts require the target type to be specified at compile-time, but metaclass variables are not assigned until runtime.
Does the original way of coding, where the item is freed by simply calling the great-great-great (etc) ancestor Free method end up effecting the descendant's destructor method?
The original code will work just fine 99% of the time, yes. Most Delphi coders are good about override'ing the destructor when it is appropriate. But that other 1% is only when you are dealing with classes that are not implemented correctly, in which case it is their author's responsibility to fix them, not your responsibility to fix the code that is calling Free() on them.
As I write this, I'm now thinking that it actually does. But I don't know why.
Polymorphic dispatch of the virtual destructor, just like when calling any other virtual method.
Why does my method of trying to typecast via the parameter which is of type class not work? Is this just not allowed?
Correct. It is illegal.
Is there another way to do this?
No (well, yes, but it involves walking an object's class structure's manually at runtime, but that requires a deep understanding of how the compiler lays out objects in memory, so I'm not going to get into that here).

Can I make the compiler fail if Create is called explicitly?

I have many singletons where I don't want the developers to call the constructor Create. Instead they should use the function Instance
TdgpBankBranch = class(TDataGroup)
strict private
class var InstanceVar : TdgpBankBranch;
private
{ Only for internal use }
constructor Create (AOwner : TComponent); reintroduce;
protected
public
class function Instance : TdgpBankBranch;
class function Is_A_Live_Singleton: boolean;
property Rec[Bank, Branch : integer]: TBankBranch read GetRec; default;
end;
I have been shifting the constructors to private. This makes the code analysers complain "Non-public constructor".
I could shift them back to public. Is there a way to make the compiler fail if an attempt is made at using the constructor ?
Moving the constructor to private will prevent other units from being able to call Create() directly, however code inside the same unit as the class will still be able to call it unhindered, due to implicit friendship within a unit. If you don't want any code outside of the class calling Create() directly, even in the same unit, then declare it as strict private so only the class itself can call it directly.
You ask how to stop the compiler from creating an object when somebody calls .create, but what you're trying to do is create a singleton, so it helps to see how others solved this.
In Delphi, singletons are often implemented via a function that's declared in the interface section and which returns an object that's declared in the implementation section of a unit. The function creates the instance if it doesn't exist yet, to provide lazy loading. Cleanup is done via the finalization section.
In your situation, instead of having an instance() function, you just create a global function that gives you an instance.
This approach probably stems from the days before classes and private sections existed, but it's pretty straightforward, and prevents the issue that you're running in to. Look at how TClipboard is implemented. This implementation is not possible in Java or C# because they don't have global functions, or the type of scoping that makes this Delphi implementation work...
Or take a look at this answer by David Heffernan:
Delphi Singleton Pattern
It's even better than TClipboard, because it hides the entire class in the implementation section, truly preventing people to create instances themselves, but you'll have to create an interface for your class.

Delphi Class Helper RTTI GetMethod

Lets say I have a sample class helper
TSampleClassHelper = class helper for TSampleClass
public
procedure SomeHelper;
end;
I do the following:
var
obj :TSampleClass;
begin
obj:=TSampleClass.Create;
obj.SomeHelper;
end;
and this works as expected.
But how can I use RTTI to invoke the helper method instead? The following does not seem to work, GetMethod returns nil.
var
obj :TSampleClass;
ctx :TRTTIContext;
rtype :TRTTIType;
rmethod :TRTTIMethod;
begin
obj:=TSampleClass.Create;
rtype:=ctx.GetType(obj.ClassType);
rmethod:=rtype.GetMethod('SomeHelper'); // rmethod is nil !
end;
So does RTTI not work for methods defined in class helpers? Is there anyway around this?
Thanks.
The reason your code returns a nil method is that the object's type does not contain a method named SomeHelper. The type that contains that method is the helper type.
So, you could write this which will return a non-nil method:
obj:=TSampleClass.Create;
rtype:=ctx.GetType(TypeInfo(TSampleClassHelper));
rmethod:=rtype.GetMethod('SomeHelper');
Of course, you should immediately see the first problem, namely the use of a compile time specified type, TSampleClassHelper. Can we use RTTI to discover TSampleClassHelper at run time based on the type of the instance? No we cannot, as I will explain below.
Even if we put that to one side, as far as I can see, there's no way to invoke the method using RTTI. If you call rmethod.Invoke(obj, []) then the code in TRttiInstanceMethodEx.DispatchInvoke blocks an attempt to call the helper method. It blocks it because it decrees that the type of the instance is not compatible with the class of the method. The pertinent code is:
if (cls <> nil) and not cls.InheritsFrom(TRttiInstanceType(Parent).MetaclassType) then
raise EInvalidCast.CreateRes(#SInvalidCast);
Well, you can obtain the code address of the helper method with rmethod.CodeAddress but you'll need to find some other way to invoke that method. It's easy enough to cast it to a method with the appropriate signature and invoke it. But why bother with rmethod.CodeAddress in any case? Why not use TSomeHelperClass.SomeMethod and cut RTTI out of the loop?
Discussion
Helper resolution is performed statically based on the active helper at the point of compilation. Once you attempt to invoke a helper method using RTTI there is no active helper. You've long since finished compiling. So you have to decide which helper class to use. At which point, you don't need RTTI.
The fundamental issue here is that class helper method resolution is fundamentally a static process performed using the context of the compiler. Since there is not compiler context at run time, class helper method resolution cannot be performed using RTTI.
For more insight into this have a read of Allen Bauer's answer here: Find all Class Helpers in Delphi at runtime using RTTI?

Class constructor not called when class registration is done in that class constructor

I am writing a simple dependency injection / inversion of control system based on a TDictionary holding abstract class references with their respective implementor classes.
My goals are:
Avoid direct instantiation by type (obviously).
Inclusion of a class' unit in the dpr should be enough to have it registered and be available for selection and instantiation through the di/ioc system.
Declare concrete implementing classes in implementation section only.
Use class constructors instead of initialization sections.
Btw, I am aware that using class constructors to take advantage of smart linking and wanting the inclusion of a unit to be enough to make a class available are defeating each other. I want to use class constructors instead of initialization sections for other reasons as well. And I would like to keep all class initialization/registration code together instead of having to split it between the class constructor and initialization section.
Problem
I want the registration of the class into the factory to be in the class constructor. Unfortunately, the compiler doesn't think the class is "touched" by just using its type in its own class constructor.
When I put the registration function in the initialization section, then the compiler does think the class is touched and calls the class constructor. But that defeats the object of my exercise of keeping all class initialization code in the class constructor.
Two questions
Should the compiler consider the use of the class in its own class constructor "touching the class" or is that too much to expect the compiler to do?
Does anybody have any clever ideas on how I can still achieve my goals without using the initialization section?
Example
The abstract classes used in the application:
TSite = class abstract (TObject)
function GetURL: string; virtual; abstract;
property URL: string read GetURL;
end;
TSites = class (TList<TSite>);
TThisApplication = class abstract (TObject)
function Sites: TSites; virtual; abstract;
end;
The concrete implementing class (declared in the implementation section!) for TThisApplication
TThisApplicationConcrete = class(TThisApplication)
class constructor ClassCreate;
strict private
FSites: TSites;
function Sites: TSites; override;
end;
class constructor TThisApplicationConcrete.ClassCreate;
begin
RegisterImplementorClass(TThisApplication, TThisApplicationConcrete);
end;
function TThisApplicationConcrete.Sites: TSites;
var
SiteList: TSites;
begin
if not Assigned(FSites) then begin
SiteList := TSites.Create; // Change to use factory
//RetrieveSites(SiteList);
FSites := SiteList;
end;
Result := FSites;
end;
The function to get an instance of TThisApplication:
function ThisApplication: TThisApplication;
var
ImplementorClass: TClass;
begin
ImplementorClass := GetImplementorClass(TThisApplication);
if Assigned(ImplementorClass) then begin
Result := ImplementorClass.Create as TThisApplication;
end else begin
Result := nil;
end;
end;
This is currently coded in a separate function, but it w/could be moved to the factory.
Full example code
If anybody would like to experiment, I have the full code of my test projects available at : http://www.bjsoftware.com/delphistuff/stackoverdlow/classconstructors.zip
Zip contents:
4 projects all using the same source files, differing only in conditional defines (that's why the dproj's are also included)
4 source files
groupproj and its dsk with all 4 projects
RunTestApps.cmd to run all 4 projects
Results.txt with the output of my run of the RunTestApps.cmd
WriteUp.txt with the text of this question
Please bear in mind that at all times you need to do a "Build All Projecs" because all dcu's and exe's are going to the source dir and otherwise you are going to face a lot of errors and/or confusion because the exe isn't doing what its name indicates.
This is as expected. As Uwe pointed out, a self-referential class constructor isn't enough to trigger inclusion. Placing the reference in the initialization section will do the trick since that is outside the class itself. Trying to self-reference a class for inclusion is akin to trying pull yourself out of a deep hole by pulling on your own suspenders.
As long as you don't use the class anywhere outside the class itself, the compiler takes this as the class not used at all and hence won't call the class constructor. So I guess you have to use the intialization section instead of tweaking the code to fool the compiler. Take the pragmatic approach instead of the dogmatic one. It will be more readable anyway.
I think you expect the class constructor to work differently than it has been designed to. Class constructor don't get called "just before" the first create. (Not in WIN32 delphi at least). If a class is referenced, its class constructor will run before the unit's initialization code.
If the only reference that you have to your class happens to be inside said class, then no code actually linked into your application refer to said class. Therefore, its class constructor will never get called.
I believe register functions belongs to the initialization section. Having the register function there will force the class constructor to also be executed. I don't see why you would want/require the register code to be placed into the class constructor.
If you want more information about the way class constructor/destructor works, you can read this pretty good article by Allen Bauer:
http://blogs.embarcadero.com/abauer/2009/09/04/38899

Delphi 6: Force compiler error on missing abstract class methods?

I'm using Delphi Pro 6. Right now, the only way to know if a class is missing a base class abstract method is to wait for the IDE to emit a "constructing instance of {derived class} containing abstract method {base class.abstract method name}" warning or to wait for a runtime Abstract Error method when an attempt to call the missing method is made. The former isn't sufficient since it only finds warnings for those derived classes actually constructed in the current project. The latter is just plain painful.
It would be so much better if Delphi output a fatal warning for all classes that do not declare/implement a base class abstract method immediately. Does anyone know a way to set this up or a plug-in that does this?
Thanks.
I've found the simplest way to do this is to add a section in the unit initialization area using a conditional define that creates an instance of each class that you think shouldn't have any abstract methods:
{$IFDEF CheckAbstracts}
initialization
TSubclass1.Create(params);
TAbstractClass1.Create(params); // Gives constructing instance of {derived class} containing abstract method warning
{$ENDIF}
Compile with the CheckAbstracts conditional, and you will get warnings whenever you have an incompletely implemented class.
A class containing abstract methods is only dangerous if you instantiate the class, so Delphi's warning is spot-on. You only get the abstract-error run time exception if you ignored at least one "instantiating class with abstract methods".
It's valid to not implement these methods. You might intend to implement the abstract method in yet another subtype.
A later version of Delphi/Win32 (I don't remember which) introduced formal abstract classes, which make it clear when you do and do not intend to instantiate the type. If you're rigorous about using this, the feature you request would then make sense. But for D6 it is not clear.

Resources