2

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?

5
  • This just tells the compiler to treat the untyped var param as though was of type TComponent Commented Feb 24, 2022 at 6:20
  • Isnt it a violation of Borland's/Embarcadero's licensing to post the entire VCL source code on an open source website? Commented Feb 24, 2022 at 16:03
  • @RemyLebeau: GitHub responds to DMCA complaints, but it seems like the original repository was GNU GPL’d. Commented Feb 24, 2022 at 16:24
  • @KaiBurghardt "the original repository was GNU GPL’d" - not by Borland, it wasn't. They NEVER open-sourced their proprietary code. They provide their framework source code with the IDE for reference purposes only, but not for open distribution. Commented Feb 24, 2022 at 16:42
  • @RemyLebeau: Well, then your answer post is in violation of copyright, too. You cannot translate a foreign work without the author’s permission. Kindly inform Borland Inc. [i. e. Micro Focus now] of your, Groger’s, and the GH repository’s violations yourself, so they can file DMCA complaints if they think it’s warranted. Commented Feb 24, 2022 at 16:52

2 Answers 2

3
  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.
Sign up to request clarification or add additional context in comments.

Comments

1

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));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.