I am looking at the source code for CodeGear C Builder header files. In Source/vcl/forms.pas
I find the following lines of code:
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
Instance: TComponent;
begin
Instance := TComponent(InstanceClass.NewInstance); // 메타클래스 이용하여, 인스턴스화
TComponent(Reference) := Instance;
try
Instance.Create(Self); // 폼 생성
except
TComponent(Reference) := nil;
raise;
end;
if (FMainForm = nil) and (Instance is TForm) then
begin
TForm(Instance).HandleNeeded; // 윈도우핸들을 생성
FMainForm := TForm(Instance);
end;
end;
Contextually, what I think is happening is that this procedure creates an instance of type InstanceClass
and returns that instance through Reference
. In my call, InstanceClass
is not TForm
, so the second half doesn't matter.
I am confused by TComponent(Reference) := Instance;
. Syntactically, what is happening here? Is this assignment by reference? Is this assigning a new TComponent
with the instantiator argument Reference
being assigned the value? Is TComponent()
a type casting?
CodePudding user response:
- In the
procedure
’s signature the formal parameterreference
does not indicate a data type, but is declared as avar
iable parameter. - Typeless parameters are not legal in Pascal, but permitted in dialects such as GNU Pascal and FreePascal. There, such variable parameters accept actual parameters of any data type. The compiler will not enforce/restrict permissible data types, but it must be addressable (i. e. literals are not permitted).
dataTypeName(expression)
is indeed a typecast (also illegal in Pascal, but allowed by some dialects). Specifically,dataTypeName(variableName)
is a variable typecast. It will be treated as ifvariableName
was of the named data type. This is necessary, because in this particular casereference
has no associated data type. No associated data type means, there is no agreed rule in how to access the variable in question (i. e. any read/write access is impossible).- The procedure probably creates an instance of
TComponentClass
, i. e. the data type of the parameterInstanceClass
, but there you should really read the documentation of theNewInstance
method. I can only tell you it’s a descendant ofTComponent
otherwise it hardly makes sense to typecast to an unrelated class.
CodePudding user response:
The Reference
parameter is an untyped var
parameter. In C terms, it is roughly equivalent to void*
, ie the address of any variable can be bound to it. The code is type-casting the Reference
to the equivalent of TComponent*&
or TComponent**
and then assigning the Instance
variable (a TComponent*
pointer) to the caller's passed variable.
The code is roughly equivalent to the following in C (except that metaclasses and virtual constructors don't exist in C , so this code is actually not usable in C ):
void __fastcall TApplication::CreateForm(TComponentClass* InstanceClass, void* Reference)
{
// this just allocates a block of memory of the required size...
TComponent* Instance = static_cast<TComponent*>(InstanceClass->NewInstance());
// *static_cast<TComponent**>(Reference) = Instance;
reinterpret_cast<TComponent*&>(Reference) = Instance;
try
{
// This is calling the class' virtual constructor
// on the allocated memory. In C , this would be
// similar to calling 'placement-new' if the class
// type was known statically here...
// new(Instance) InstanceClass->ClassType()(this);
Instance->Create(this);
}
catch (...)
{
// *static_cast<TComponent**>(Reference) = NULL;
reinterpret_cast<TComponent*&>(Reference) = NULL;
throw;
}
if ((!FMainForm) && (dynamic_cast<TForm*>(Instance) != NULL))
{
static_cast<TForm*>(Instance)->HandleNeeded();
FMainForm = static_cast<TForm*>(Instance);
}
}
// Application.CreateForm(TForm, Form1);
Application->CreateForm(__classid(TForm), reinterpret_cast<void*>(&Form1));