2012-05-13 98 views
-1

我希望類類型的函數使用類型轉換。 我有基(TBase),派生(TDer)和類型轉換(TMyType)類。具有類函數的類型轉換

版本:德爾福7

TBase = class; 
TDer = class; 
TMyType = class; 

TBase = class 
    function Say : String; 
    class function MYType:TMyType; 
end; 

TDer = class(TBase) 
    a: string; 
    b: string; 
    function Say2 : String; 
end; 

TMyType=class(TBase) 
    class function AsDer:TDer; 
end; 

{ TBase } 

class function TBase.MYType: TMyType; 
begin 
    Result:=TMyType(Self); 
end; 

function TBase.Say: String; 
begin 
    Result:='TBase'; 
end; 

{ TDer } 

function TDer.Say2: String; 
begin 
    Result:='TDer'; 
end; 

{ TMyType } 

class function TMyType.AsDer: TDer; 
begin 
    Assert(Assigned(Self)); 
    Result := TDer(Self) ; 
end; 

樣品用量低於,它的調用方法,但是當設置/獲取現場的引發錯誤。

procedure TForm1.Button1Click(Sender: TObject); 
var 
    b,c:TBase; 
begin 
    b:=TDer.Create; 
    c:=b.MYType.AsDer; 

    ShowMessage(b.MYType.AsDer.Say2); // OK. Running  
    if (@b<>@c) then ShowMessage('Not Equal'); // Shows message, Why ? 
    b.MYType.AsDer.a:='hey'; // Error 

    FreeAndNil(b); 
end; 

你有什麼想法嗎?

回答

6

最根本的問題是在這裏:

class function TBase.MYType: TMyType; 
begin 
    Result:=TMyType(Self); 
end; 

這是一個類的方法,因此Self類,而不是一個實例。將它鑄造成一個實例並不會如此。在AsDer類函數中發生的錯誤是完全相同的。

展望細節,調用

b.MYType.AsDer.Say2 

是良性的,似乎很好地工作,因爲它並不是指Self。你同樣可以寫TDer(nil).Say2,而且代碼也可以毫無問題地工作。現在,如果函數Say2被稱爲Self,那麼它被引用爲一個實例,那麼會有運行時錯誤。

@b<>@c 

總是計算爲true,因爲您正在比較兩個不同的局部變量的位置。

b.MYType.AsDer.a 

是一個運行時錯誤,因爲AsDer不返回TDer一個實例。所以當你試圖寫入a時,你有一個運行時錯誤。這是因爲您指的是Self,這就是爲什麼此代碼失敗,但之前致電Say2的號碼沒有。


我不太確定你在這裏做什麼,但它看起來都是錯的。即使您使用的是實例方法而不是類方法,但將基類實例劃分爲派生類實例根本就是錯誤的。如果某種東西是錯誤的類型,則不會有大量的投射將其轉化爲正確的類型。

此外,您不應該編寫代碼,其方法爲TBase,假設它的類型爲TDerived。基類應該完全不知道它的派生類。這是面向對象設計的基本原則之一。

0

下面是編輯後的新版本:

TBase = class; 
TDer = class; 
TMyType = class; 

TBase = class 
    MYType:TMyType; 
    constructor Create; 
    destructor Destroy; 
    function Say : String; 
end; 

TDer = class(TBase) 
    a: string; 
    b: string; 
    function Say2 : String; 
end; 

TMyType=class 
public 
    T: TObject; 
    function AsDer:TDer; 
end; 

{ TBase } 

constructor TBase.Create; 
begin 
    MYType:=TMYType.Create; 
    MYType.T:=TObject(Self); 
end; 

destructor TBase.Destroy; 
begin 
    MYType.Free; 
end; 

function TBase.Say: String; 
begin 
    Result:='TBase'; 
end; 

{ TDer } 

function TDer.Say2: String; 
begin 
    Result:='TDer'; 
end; 

{ TMyType } 

function TMyType.AsDer: TDer; 
begin 
    Result := TDer(T) ; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    b:TBase; 
    c:TDer; 
begin 
    b:=TDer.Create; 
    TDer(b).a:='a'; 
    c:=b.MYType.AsDer; 

    ShowMessage('b.MYType.AsDer='+b.MYType.AsDer.a+', c.a ='+ c.a); // OK. Running 
    FreeAndNil(b); 
end; 
+0

你到底想達到什麼目的? –

+0

我需要一個特殊的目標。用戶友好的類型爲程序員鑄造。 – zgn

+0

我相信這只是演示語法的演示代碼。在真實代碼中,您需要使用'is'和'as'運算符進行運行時類型檢查。不要盲目地寫'TDer(T)',你會寫'T as TDer',因此在'T'不是'TDer'的情況下引發一個可理解的運行時異常。 –