Top  Previous  Next

What is translated > class-reference type > ClassRef

In System.cs of the accompanying code to Delphi2C# there is a class TMetaClass defined. TMetaClass is the class reference type for TObject and it is the base class of all class reference types of all other classes. These class references are defined as instances of a class ClassRef, which is a generic class:



public sealed class ClassRef<Class> : TMetaClass where Class : TObject, new()



where the template parameter denotes the original class. That way for a hierarchy of classes, which are derived one from another, there is a parallel hierarchy of class references. The class references are implemented as singletons and only created, if needed. The exact definition of the ClassRef class is tricky and works only, because Delphi2C# also inserts some additional helper code into every class declaration. The following code demonstrates how a small class factory using class references is converted from Delphi to C++:




 TBase = class                           


  function GetName: String; virtual;     



 TBaseClass = class of TBase;            


 TDerived = class(TBase)                


  function GetName: String; override;    



 TDerivedClass = class of TDerived;    





function make(Base: TBaseClass): TBase;  


  result := Base.Create;                 



function testTactory: boolean;           


 s : String;                             

 p : TBase;                              


 p := make(TDerived1);                   

 result := p.GetName = 'TDerived';      







public class TBase : TObject





  public TBase() {}

  public override string ClassName() {return "TBase";}

  public override TMetaClass ClassType(){return class_id<TBase>();}

  public override TMetaClass ClassParent(){return class_id<TObject>();}

  public override TObject Create(){return new TBase();}

  public static new TBase SCreate() {return new TBase();}



// ClassRef<TBase> TBaseClass;


public class TDerived : TBase





  public TDerived() {}

  public override string ClassName() {return "TDerived";}

  public override TMetaClass ClassType(){return class_id<TDerived>();}

  public override TMetaClass ClassParent(){return class_id<TBase>();}

  public override TObject Create(){return new TDerived();}

  public static new TDerived SCreate() {return new TDerived();}



// ClassRef<TDerived> TDerivedClass;


public class TestInterface




} // class TestInterface





public class TestImplementation




public static TBase Make(TMetaClass Base)


  TBase result = null;

  result = (TBase) Base.Create();

  return result;



public static bool testTactory()


  bool result = false;

  string S = string.Empty;

  TBase P = null;

  P = Make(TDerived1->ClassType());

  result = P.GetName == "TDerived";

  return result;





The central point in this code is the call of the class_id-function:


P = make(class_id<TDerived>());


The class_id-function delivers class references. In the example the class_id-function delivers the class reference to the class TDerived.



If TDerived wouldn't have a standard constructor, instead of the line


static TDerived* Create() {return new TDerived();}


the line


static TDerived* Create() {ThrowNoDefaultConstructorError(ClassName()); return nullptr}


would have been written. If TDerived were an abstract class, the line would have been:


static TDerived* Create() {ThrowAbstractError(ClassName()); return nullptr}



Other uses of Delphi class references are reproduced in C++ too. For example:


  ClassRef := Sender.ClassType;


  while ClassRef <> NIL do


    s := ClassRef.ClassName);

    ClassRef := ClassRef.ClassParent;



is converted to:


TClass ClassRef = Sender->ClassType();


while(ClassRef != nullptr)


  s = ClassRef->ClassName();

  ClassRef = ClassRef->ClassParent();




However only a minimal frame for class reference manipulations is created and there have to be standard constructors for all classes with used class references.




This page belongs to the Delphi2C# Documentation

Delphi2C# home  Content