Pascal - 函数调用赋值

Pascal - Assignment to Function Call

我正在查看 CodeGear C++ Builder 头文件的 source code。在 Source/vcl/forms.pas 中,我找到以下代码行:

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;

从上下文来看,我认为正在发生的事情是此过程创建了一个 InstanceClass 类型的实例,并且 returns 该实例通过 Reference。在我的调用中,InstanceClass 不是 TForm,所以后半部分无关紧要。

我被TComponent(Reference) := Instance;搞糊涂了。 从句法上讲,这里发生了什么?这个赋值是引用吗?这是在为实例化器参数 Reference 分配值时分配新的 TComponent 吗? TComponent() 是类型转换吗?

  1. procedure的签名中,形式参数reference不表示数据类型,而是声明为variable参数。
  2. 无类型参数在 Pascal 中是不合法的,但在 GNU Pascal 和 FreePascal 等方言中是允许的。 在那里,这样的 variable parameters 接受 any 数据类型的实际参数。 编译器不会 enforce/restrict 允许的数据类型,但它必须是 可寻址的 (即不允许文字)。
  3. dataTypeName(expression) 确实是类型转换(在 Pascal 中也是非法的,但某些方言允许)。 具体来说,dataTypeName(variableName) 是一个 variable typecast。 它将被视为 variableName 是指定的数据类型。 这是必要的,因为在这种特殊情况下 reference 没有关联的数据类型。 没有关联的数据类型意味着,在如何访问相关变量方面没有一致的规则(即任何 read/write 访问都是不可能的)。
  4. 过程 可能 创建了 TComponentClass 的一个实例,即。 e.参数 InstanceClass 的数据类型,但您真的应该阅读 NewInstance 方法的文档。 我只能告诉你它是 TComponent 的后代,否则将类型转换为不相关的 class.
  5. 几乎没有意义

Reference 参数是一个未类型化的 var 参数。在C++术语中,它大致等价于void*,即任何变量的地址都可以绑定到它。代码是 type-casting Reference 相当于 TComponent*&TComponent**,然后将 Instance 变量(TComponent* 指针)分配给调用方传递的变量。

这段代码大致等同于C++中的以下代码(除了C++中不存在元类和虚构造函数,所以这段代码实际上在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));