【发布时间】:2013-01-15 13:06:32
【问题描述】:
我需要澄清一下 Delphi 类型转换
我写了一个有两个类的例子:TClassA 和 TClassB,TClassB 派生自 TClassA。
代码如下:
program TEST;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
TClassA = class(TObject)
public
Member1:Integer;
constructor Create();
function ToString():String; override;
end;
type
TClassB = class(TClassA)
public
Member2:Integer;
constructor Create();
function ToString():String; override;
function MyToString():String;
end;
{ TClassA }
constructor TClassA.Create;
begin
Member1 := 0;
end;
function TClassA.ToString: String;
begin
Result := IntToStr(Member1);
end;
{ TClassB }
constructor TClassB.Create;
begin
Member1 := 0;
Member2 := 10;
end;
function TClassB.MyToString: String;
begin
Result := Format('My Values is: %u AND %u',[Member1,Member2]);
end;
function TClassB.ToString: String;
begin
Result := IntToStr(Member1) + ' - ' + IntToStr(Member2);
end;
procedure ShowInstances();
var
a: TClassA;
b: TClassB;
begin
a := TClassA.Create;
b := TClassB(a); // Casting (B and A point to the same Memory Address)
b.Member1 := 5;
b.Member2 := 150; // why no error? (1)
Writeln(Format('ToString: a = %s, a = %s',[a.ToString,b.ToString])); // (2)
Writeln(Format('Class Name: a=%s, b=%s',[a.ClassName,b.ClassName])); // (3)
Writeln(Format('Address: a=%p, b=%p',[@a,@b])); // (4)
Writeln(b.MyToString); // why no error? (5)
readln;
end;
begin
try
ShowInstances;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
程序输出为:
ToString: a = 5, a = 5
Class Name: a=TClassA, b=TClassA
Address: a=0012FF44, b=0012FF40
My Values is: 5 AND 150
(1) Member2 地址是什么?这可能是“访问冲突”吗?
(2) ok,ToString() 方法指向同一个地址
(3) 为什么 a 和 b 的 ClassName 相同?
(4) ok,a和b是两个不同的变量
(5)如果b是TClassA,为什么可以使用“MyToString”方法?
【问题讨论】:
-
这些问题有点没有意义。你的演员是非法的。不要这样做。
-
非法不代表没有意义。
-
即使我误用了演员表,我认为编译器允许你这样做是有原因的。
-
@AndreaBoc - 通过进行不安全的类型转换,您对编译器说“闭嘴。我知道我在做什么”。编译器只是服从。
-
你可以用这些信息做什么?你永远不会使用这个代码。一旦你打破了规则,你就无法以稳健的方式进行推理。编译器可能会以不可预知的方式运行。