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 parameterreferencedoes not indicate a data type, but is declared as avariable 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 ifvariableNamewas of the named data type. This is necessary, because in this particular casereferencehas 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 theNewInstancemethod. I can only tell you it’s a descendant ofTComponentotherwise 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));
