In Delphi, what is the equivalent of C++'s dynamic_cast
, reinterpret_cast
, and static_cast
operators (especially when used on objects)?
Yes, dynamic_cast is a code smell, but so is adding functions that try to make it look like you have a good polymorphic interface but are actually equal to a dynamic_cast i.e. stuff like can_put_on_board .
While typeid + static_cast is faster than dynamic_cast , not having to switch on the runtime type of the object is faster than any of them.
dynamic_cast runs at about 14.4953 nanoseconds. Checking a virtual method and static_cast ing runs at about twice the speed, 6.55936 nanoseconds.
In C++, dynamic casting is, primarily, used to safely downcast; i.e., cast a base class pointer (or reference) to a derived class pointer (or reference). It can also be used for upcasting; i.e., casting a derived class pointer (or reference) to a base class pointer (or reference).
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!";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With