What is the equivalent of dynamic_cast in Delphi?

  • A+

In Delphi, what is the equivalent of C++'s dynamic_cast, reinterpret_cast, and static_cast operators (especially when used on objects)?



Most of the time, in Delphi, a cast is a reinterpret_cast, i.e. the bits and bytes of one type are reinterpreted as if it were another type, e.g. Integer(myEnum) or Pointer(MyDynamicArrayVar).

Some casts cut off bits, i.e. Integer(MyInt64) will cut off the top 32 bits of the Int64, and the top bit of the lower 32 bits will become the new sign bit. Some casts expand, e.g. Integer(myByte), although such conversions to a larger type don't require a cast. Conversions from, e.g. Integer to floating point don't require casts either.

But sometimes it is not a reinterpret_cast, and the cast does a real conversion (e.g. a cast from string to PChar converts if the string is empty; a cast from AnsiString to UTF8String converts the contents to UTF-8, and UnicodeString(myAnsiChar) converts even twice, from AnsiChar to AnsiString to UnicodeString, although these steps may not all be visible). And some casts are simply not allowed (e.g. Int64(MyDouble) or certain casts where the sizes don't match).

Note that with operator overloading (mainly for records), you can have explicit and implicit conversions too. The explicit conversions take the form of a cast. The implicit conversions can be forced by "casting" too.

The form of a cast in Delphi is always typename(cast_object), which casts cast_object to typename.

Some invalid casts can be circumvented using pointers. If you do something like:

MyInt64 := PInt64(@MyDouble)^; 

where PInt64 is a pointer to Int64 and the other types are obvious,

then you can cast a Double to an Int64. Note that no actual pointer juggling is done. The conversion is direct, as if you had done

MyInt64 := Int64(MyDouble); // Invalid typecast -- except in some versions 

There is no extra kind of static_cast in Delphi. I personally wish we had such explicit casts like in C++. Delphi's are more like in C.


If the types involved are classes or interfaces, then there are equivalents using the as and is keywords. For example:

myEdit := MyTObject as TEdit; myIntf := MyObj as ISomeInterface; 

both dynamic upcasts. Unlike in C++, these will raise (throw in C++) an EInvalidCast exception if MyTObject is not an instance of TEdit, or if myObj doesn't implement ISomeInterface. It is otherwise equivalent to C++:

TEdit *myEdit = dynamic_cast<TEdit *>(MyTObject); if (myEdit == NULL) throw ... 

Querying, like often done with dynamic_cast in C++, can be done with is:

if MyObject is TEdit then   TEdit(MyObject).Text := 'Hello, world!'; 

That is more or less equivalent to this "pattern" in C++:

TEdit *e = dynamic_cast<TEdit *>(MyObject); if (e != NULL)     e->Text = "Hello, world!"; 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: