Based on your code
unit InvoiceHeaderClass;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,forms;
var
NextInvNum:integer; {Global invoice number that can be set from the outside but will be incremented by the object}
type
Tinvheader = class
Private
InvNum: integer;
SalesNum: integer;
CustCode: string;
CustName: string;
CustAddr1: string;
CustAddr2: string;
CustCity: string;
CustState: string;
CustZip:string;
CustPhone:string;
InvDate:TDateTime;
HeadScreen:TForm;
Public
Constructor Create();
end;
implementation
Constructor Tinvheader.Create();
begin
InvNum:= NextInvNum;
inc(NextInvNum); {Increment global invoice number variable so the next time a header is created it has a new number}
SalesNum:= 0;
CustCode:= '';
CustName:= '';
CustAddr1:= '';
CustAddr2:= '';
CustCity:= '';
CustState:= '';
CustZip:= '';
CustPhone:= '';
InvDate:=now();
end;
end. what do you expect that happens with the above code? take your time and think about then read what happens below.
What happens is, as always, dependent heavily on the compiler mode you are using, in objfpc mode the above code declares a new
overloaded constructor named Create with no parameters and thats because the overload keyword is not mandatory in that mode. In delphi mode a warning should be raised that the new constructor is hiding the old one since no overloading is defined and no override is given and the constructor declaration is different from the old one the compiler does what it can to compile the program and that is to create a second one with the same that is to be used for this class only and since there is a naming conflict it informs you that the newer constructor will be used in all cases.
In both cases the old constructor that has code to internally initialize the various private fields is not called from your new constructor at all.
You are lucky because in most cases the internal fields are lazy created but there are fields initialized in the constructors and those initialization are never executed IF you call the new constructor correctly.
And then you ask about calling the
TForm.Create(nil)
which in objfpc mode should never be your constructor but always the old constructor declared in the TForm class(overloaded takes care of this). In the case of delphi mode since you are using the tform class instead of TInvHeader class it will have no idea about the new constructor, because no override is ever declared and the last known virtual constructor will be executed. In the case that you have correctly used the new class (TinvHeader) if you pass the nil parameter I think the correct behavior is to call the old constructor although an exception that it can't find the method would be acceptable as well in this case and I can't remember for sure which one is the correct behavior.
The solution is to properly override the old constructor and in there call the old one. Although there are cases where calling inherited might not be very smart you should never,
ever avoid calling the inherited constructor, think of it as a mandatory obligation of the override. To sum things up the correct way to write your form's constructor is the following.
unit InvoiceHeaderClass;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,forms;
var
NextInvNum:integer; {Global invoice number that can be set from the outside but will be incremented by the object}
type
Tinvheader = class
Private
InvNum: integer;
SalesNum: integer;
CustCode: string;
CustName: string;
CustAddr1: string;
CustAddr2: string;
CustCity: string;
CustState: string;
CustZip:string;
CustPhone:string;
InvDate:TDateTime;
HeadScreen:TForm;
Public
Constructor Create(aOwner:TComponent);override;
end;
implementation
Constructor Tinvheader.Create(aOwner:TComponent);
begin
inherited Create(aOwner); // or inherited; both should have the same effect but the second requires the parameter name to be the same with the old constructor as well If I remember correctly.
end;At this point you might observe that the name of the parameter I use is different from the the one used in the TForm class, that is not a problem as long as the type of the parameter is the same.