在Delphi中,大部分情况下,类型转换是一个 reinterpret_cast
,也就是将一种类型的位和字节重新解释为另外一种类型,例如 Integer(myEnum)
或 Pointer(MyDynamicArrayVar)
。
有些类型转换会截断一些位,比如 Integer(MyInt64)
会截断 Int64
的顶端32位,并且保留剩余32位中的顶端位作为新的符号位。还有些类型转换会扩展类型,例如 Integer(myByte)
,虽然这种从小类型到大类型的转换不需要进行类型转换。从 Integer
到浮点数之类的转换也不需要进行类型转换。
但有时候并不是一种 reinterpret_cast
,而是真正的转换(例如从 string
到 PChar
的转换,如果字符串为空则不进行转换;从 AnsiString
到 UTF8String
的转换将内容转换为 UTF-8 编码,以及 UnicodeString(myAnsiChar)
的转换甚至进行了两次,从 AnsiChar
到 AnsiString
,再从 AnsiString
到 UnicodeString
,尽管这些步骤中的某些步骤可能不可见)。有些转换是不允许的(例如 Int64(MyDouble)
或者某些大小不匹配的类型转换)。
请注意,通过运算符重载(主要用于记录类型),您也可以进行显式和隐式转换。显式转换采用了类型转换的形式。强制转换亦可实现隐式转换。
在Delphi中,类型转换总是采用 typename(cast_object)
的格式,将 cast_object
转换为 typename
。
一些无效的类型转换可以通过指针来规避。如果您执行以下操作:
MyInt64 := PInt64(@MyDouble)^;
其中PInt64
是指向Int64
的指针,其他类型显而易见,
然后您可以将Double
强制转换为Int64
。请注意,没有实际的指针操作。转换是直接的,就像您已经完成了。
MyInt64 := Int64(MyDouble); // Invalid typecast -- except in some versions
在Delphi中没有额外的static_cast
类型转换。我个人希望我们有像C++中那样明确的类型转换。Delphi的类型转换更像是C语言。
如果涉及的类型是类或接口,则可以使用as
和is
关键字进行等效转换。例如:
myEdit := MyTObject as TEdit;
myIntf := MyObj as ISomeInterface;
两者都是动态向上转型。与C++不同的是,如果MyTObject
不是TEdit
的实例,或者myObj
没有实现ISomeInterface
,则会引发(在C++中抛出)EInvalidCast
异常。否则,它与C++等效:
TEdit *myEdit = dynamic_cast<TEdit *>(MyTObject);
if (myEdit == NULL) throw ...
在IT技术中,我们常常使用C++的dynamic_cast
来查询信息,而在Python中,我们可以使用is
进行查询:
if MyObject is TEdit then
TEdit(MyObject).Text := 'Hello, world!';
这可以近似看作是 C++ 中的“模式”:
TEdit *e = dynamic_cast<TEdit *>(MyObject);
if (e != NULL)
e->Text = "Hello, world!";
dynamic_cast
的操作符 -is
和as
操作符。if obj is T then
相当于if (dynamic_cast<T*>(obj) != NULL)
,而obj as T
相当于T* pT = dynamic_cast<T*>(obj); if (pT == NULL) throw ...;
。 - Remy Lebeau&dynamic_cast<T&>(*ptr)
- Yakk - Adam NevraumontmyEdit := TEdit(MyTObject)
,这就像是对象的static_cast
。 - Graymatter