Home > Back-end >  Pascal - Assignment to Function Call
Pascal - Assignment to Function Call

Time:02-25

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:

  1. In the procedure’s signature the formal parameter reference does not indicate a data type, but is declared as a variable parameter.
  2. 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).
  3. 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 if variableName was of the named data type. This is necessary, because in this particular case reference 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).
  4. The procedure probably creates an instance of TComponentClass, i. e. the data type of the parameter InstanceClass, but there you should really read the documentation of the NewInstance method. I can only tell you it’s a descendant of TComponent 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));
  • Related