现有这样的类型定义及实现:type
TClass1 = class
public
procedure test;virtual;
end;procedure TClass1.test;
begin
ShowMessage('1');
end;type
TClass2 = class(TClass1)
public
procedure test;override;
end;procedure TClass2.test;
begin
inherited;
ShowMessage('2');
end;声明变量a为TClass2,如:
var
a: TClass2;
begin
....
a.test; <--------------> TClass1(a).test <-----------> (a as TClass1).test
//请问上述三总写法的区别。
//及当a声明为TClass2时,在执行test方法时,如果只执行TClass1中的实现?
end;
TClass1 = class
public
procedure test;virtual;
end;procedure TClass1.test;
begin
ShowMessage('1');
end;type
TClass2 = class(TClass1)
public
procedure test;override;
end;procedure TClass2.test;
begin
inherited;
ShowMessage('2');
end;声明变量a为TClass2,如:
var
a: TClass2;
begin
....
a.test; <--------------> TClass1(a).test <-----------> (a as TClass1).test
//请问上述三总写法的区别。
//及当a声明为TClass2时,在执行test方法时,如果只执行TClass1中的实现?
end;
TClass1(a).test:将类强制转换为TClass1,这里应该调用的是TClass1的方法
(a as TClass1).test:好象与上面的没区别,待我测试一下看
第三种写法是DELPHI中的
如果你这样写的话,它们是一点区别也没有的!
你可以写第三句前在一句if (a is TClass1) then
这样就安全的多了!
----------------
没有区别,他是通过虚函数表查找执行的函数的,
无论你怎么转型他还是执行同一个函数。//及当a声明为TClass2时,在执行test方法时,如果只执行TClass1中的实现?
-------------------------------------------------------------------
var
a: TClass2;
begin
a := TClass2(TClass1.Create()); //-
TClass1(a).test();
end; 个人认为不提倡这种用法,
向下类型转换是不安全的。
这样是好的做法:)
晕了,,,>>>向下类型转换是不安全的。
倒底是向下还是向上?我刚才一直在说向上:)
a := TClass2(TClass1.Create()); //-
只有这样创建才可能在执行test方法时,执行TClass1中的实现;
ob: b;b := (oa as b); // ok改變了尋址空間 由較大的地址范圍->較小地 而且還是繼承關系 子類是有一份復類地data地 所以 是安全地 而反過來則不一定了。
如果像你那样用TClass1.Create的话
那跟声明
aa: TClass1没什么区别了虽然在创建后强制转换到了TClass2,但我想,执行任何TClass2中实现的方法都会抱错(直觉认为)
abstract函数呢?
abstract函数呢?
abstract 必須是 virtual or dynamic method..抽象的 表示不用在本處顯示,只是聲明一個接口而已,達到接口的目的..
-------------------------------------------------------------------
var
a: TClass2;
begin
a := TClass2(TClass1.Create()); //-
TClass1(a).test();
end; 个人认为不提倡这种用法,
向下类型转换是不安全的。
======================================================================这样确实不安全
但是这样应该没啥问题var
a: TClass2;
begin
a:=TClass2.Create;
Tclass1(integer(a.ClassParent)-76).test;
a.free;
end;
在运行时,object必需是class表示的类或其后裔类的实例,或者是nil;否则引发异常。如果object的声明类型与class无关,即它们二者各自独立并且其中任意一个不是另一个的祖先,那么将导致编译错误。
至于abstract函数是纯虚函数,正如beyondtkl(大龙驹<學,無涯>) 所说,只是提供一个函数接口,为的就是达到函数借口复用的目的,所有的实现都是在子类当中完成的。
例如:在Tparent中定义了一个纯虚函数test,Tchild1和Tchild2都是他的子类,非别有实现,那么创建两个子类的对象child1和child2,TParent(child1).test和TParent(Child2).test的调用结果是不一样的。但是都可以用.test这个函数名字来调用,例如函数的参数是TParent的时候,就会给函数的调用带来很大的便利,这就是所谓的函数借口复用...
至于abstract函数是纯虚函数,正如beyondtkl(大龙驹<學,無涯>) 所说,只是提供一个函数接口,为的就是达到函数借口复用的目的,所有的实现都是在子类当中完成的。
例如:在Tparent中定义了一个纯虚函数test,Tchild1和Tchild2都是他的子类,非别有实现,那么创建两个子类的对象child1和child2,TParent(child1).test和TParent(Child2).test的调用结果是不一样的。但是都可以用.test这个函数名字来调用,例如函数的参数是TParent的时候,就会给函数的调用带来很大的便利,这就是所谓的函数借口复用...
a: TClass2;
begin
a:=TClass2.Create;
Tclass1(integer(a.ClassParent)-76).test; // <--------- 为什么是-76呀??这句给解释一下:)
a.free;
end;
刘艺的《Delphi面向对象编程思想》一书中好像有详细讲述,可惜我手头上没这本书!
这本书我倒是有,现在没心情重看了:)
放口袋里了:)主页又没什么东西,没开了。 piantang(菠菜汤)好熟悉的名字。