2009-08-05 11 views
2

なぜ以下のコードでは、「成功」ではなく「失敗」メッセージが表示されるのですか?基本クラスのクラスプロシージャは、子孫のオブジェクトをインスタンス化する必要がありますか?

背景:私は、所有者オブジェクトをインスタンス化して何かをしてから解放するクラス手続きを持っています。私は、子孫オブジェクトを持っている場合

しかし、このアプローチは動作しません。

子として呼び出すことができ、基本クラスでクラス手順を提供する方法上の任意の提案?これについて間違って考えていますか?最低限のダウン

Type 
    TBase = class(TObject) 
    Protected 
     Procedure Proc1; Virtual; 
    Public 
     Class Procedure MyClassProc; 
    end; 

    Class Procedure TBase.MyClassProc; 
    Var 
    Base: TBase; 
    begin 
    Base := TBase.Create; 
    Base.Proc1; 
    Base.Free; 
    end; 

    Procedure TBase.Proc1; 
    begin 
    Assert(FALSE, 'Failed'); 
    end; 

type 
    TChild = class(TBase) 
    protected 
     Procedure Proc1; Override; 
    end; 

    Procedure TChild.Proc1; 
    begin 
    ShowMessage('Succeeded'); 
    end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    TChild.MyClassProc; 
end; 

答えて

1

ストリップすべては、あなたがそう、その結果のみTBase.Proc1()がこれまでに呼び出されます、あなただけの今までTBaseインスタンスを作成していることがわかります。 TChild.Proc1()を呼びたい場合は、TChildインスタンスを作成し、多態性がその魔法を働かせるようにする必要があります。

ただし、目的を達成するには、クラスメソッドがオブジェクトインスタンスを作成して何かを行うようにするよりも良い方法があります。たぶんあなたの質問を明確にする必要があります。ここで

+0

@mghie:こんにちは!早い時期に私はそのような質問を得ました!私は説明してみましょう:私は基本的なフォームをいくつかの特別なプロパティを列挙し、さまざまな継承されたフォームで、そのプロパティの1つは、統計的に.FRMファイルに記録されたフォームの種類でした。フォームを私のカストーンフォーム工場に登録することでした。登録のロジックは、子どもと共有するためのベースフォームのクラスにありました。フォームの種類を取得する唯一の方法は、それをインスタンス化して、それをフォーム "オブジェクト"から取得することでした。よろしく。 –

1

それは

TBase = class; 
TBaseClass = class of TBase; 

TBase = class(TObject) 
protected 
    class function GetBaseClass: TBaseClass; virtual; 

function TBase.GetBaseClass: TBaseClass; 
begin 
    Result := TBase; 
end; 

TChild = class(TBase) 
protected 
    class function GetBaseClass: TBaseClass; override; 

function TChild.GetBaseClass: TBaseClass; 
begin 
    Result := TChild; 
end; 

変更

から

Base := TBase.Create; 

Base := GetBaseClass.Create; 
に追加されます

はあなたの仕事

チアーお楽しみ

Aファム

+0

これは明らかな回避策ですが、それでも依然として質問をします。なぜこのようにするのでしょうか?なぜクラスメソッド、無料の関数ではないのですか?なぜクラス階層は**あるのですか? – mghie

+0

@mghie - これまではこれと似たモデルを使っていましたが、実行時にどのクラスを作成するか、現在のクラスを "複製"するかを決定するクラスレジストリを使用しました。 – skamradt

+0

@skamradt:多態性とクラスメソッドは一緒には行きません。とにかくインスタンスを作成する場合は、クラスの代わりにそれを渡すことはありませんか? * Clone()*については、インスタンスは複製されるので、クラスメソッドである必要はありません。 – mghie

5

あなたは、メタプログラム書き込みで簡単にそれを行うことができます! "TBase.Create"を "Self.Create"に変更します。 "self"は現在のクラスを表します。

Type 
    TBase = class(TObject) 
    Protected 
     Procedure Proc1; Virtual; 
    Public 
     Class Procedure MyClassProc; 
    end; 

    Class Procedure TBase.MyClassProc; 
    Var 
    MyObject: TBase; 
    begin 
    // MyObject := TBase.Create; 
    MyObject := Self.Create; // The Magic goes here, self is the class that's calling this method, in this case, TChild } 
    MyObject.Proc1; 
    MyObject.Free; 
    end; 

    Procedure TBase.Proc1; 
    begin 
    Assert(FALSE, 'Failed'); 
    end; 

type 
    TChild = class(TBase) 
    protected 
     Procedure Proc1; Override; 
    end; 

    Procedure TChild.Proc1; 
    begin 
    ShowMessage('Succeeded'); 
    end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    TChild.MyClassProc; 
end; 
+1

+1。私はまだ全体のアイデアが嫌いですが、少なくともこれは最小限のコードが追加されており、オーバーライドされたヘルパー機能を提供することを忘れることで苦労する危険はありません。 – mghie

関連する問題