2011-12-11 10 views
5

ObjectPascal/DelphiのC/C++静的ローカル変数と同様の機能を実現しようとしています。 のは、Cに次の機能を持ってみましょう:True C静的ローカル変数置換?

bool update_position(int x, int y) 
{ 
    static int dx = pow(-1.0, rand() % 2); 
    static int dy = pow(-1.0, rand() % 2); 

    if (x+dx < 0 || x+dx > 640) 
     dx = -dx; 
    ... 
    move_object(x+dx, y+dy); 
    ... 
} 

静的変数置き換えがコンパイルに失敗したとして、入力された定数を使用して等価ObjectPascalとコード:

function UpdatePosition(x,y: Integer): Boolean; 
const 
    dx: Integer = Trunc(Power(-1, Random(2))); // error E2026 
    dy: Integer = Trunc(Power(-1, Random(2))); 
begin 
    if (x+dx < 0) or (x+dx > 640) then 
    dx := -dx; 
    ... 
    MoveObject(x+dx, y+dy); 
    ... 
end; 

[DCCのエラー] test_f.pas(332): E2026定数式は、そうローカル変数を初期化したワンタイムパスのためのいくつかの方法がある

を期待しましたか?

+0

より賢明なオプションは、あなたの関数独自の単位を与えること、そしてそのユニットの実装するvarセクションにグローバルを宣言する可能性があります。それは、そのユニットにとってプライベートなので、その機能にはプライベートです。私は、プライベートフィールドを持つオブジェクトを使用するのではなく、これをやりたいと思っていた時代を考えても苦労します。 –

答えて

6

DelphiにはC静的変数の直接の同等物はありません。

書き込み可能な型付き定数(user1092187's answer参照)はほぼ同等です。スコープとインスタンス化のプロパティは同じですが、CまたはC++の静的変数で可能な1回限りの初期化は許可されていません。いずれにしても、書き込み可能な型の定数は、奇妙な歴史的脚注として捨てるべきだと私は思っています。

グローバル変数を使用できます。

var 
    dx: Integer; 
    dy: Integer 

function UpdatePosition(x,y: Integer): Boolean; 
begin 
    if (x+dx < 0) or (x+dx > 640) then 
    dx := -dx; 
    ... 
    MoveObject(x+dx, y+dy); 
    ... 
end; 

あなたはinitializationセクションでワンタイム初期化を実行する必要があります。このC静的変数の限られた範囲とは異なり、グローバル名前空間の混乱を作るもちろん

initialization 
    dx := Trunc(Power(-1, Random(2))); 
    dy := Trunc(Power(-1, Random(2))); 

。現代のDelphiでは、クラス内ですべてをラップし、クラスメソッド、クラス変数、class constructorsの組み合わせを使用して、グローバル名前空間を汚染しないようにすることができます。

type 
    TPosition = class 
    private class var 
    dx: Integer; 
    dy: Integer; 
    private 
    class constructor Create; 
    public 
    class function UpdatePosition(x,y: Integer): Boolean; static; 
    end; 

class constructor TPosition.Create; 
begin 
    dx := Trunc(Power(-1, Random(2))); 
    dy := Trunc(Power(-1, Random(2))); 
end; 

class function TPosition.UpdatePosition(x,y: Integer): Boolean; 
begin 
    // your code 
end; 
+0

答えのThx、デイビッド。私は、あなたが結局言及したように、グローバル変数を避けるためにローカル変数を使うことを強調しました。アプリはスレッドセーフであることを念頭に置いて作成する必要があります。おそらく、クラスラップの回避策を使うつもりです。 –

+0

静的な統計はスレッドセーフではありません。また、クラスラッピングのアプローチはスレッドセーフではありません。何らかの形式のロックまたはロックフリーのコーディングが必要になります。 –

+0

'class constructor TPosition.Create'と 'classic'' constructor TPosition.Create'の違いは何ですか? –

4

"Writable typed constants"を有効にする:

{$J+} 
procedure abc; 
const 
    II: Integer = 45; 

begin 
    Inc(II); 
    ShowMessage(IntToStr(II)); 
end; 
{$J-} 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    abc; 
    abc; 
    abc; 
end; 
+0

これは実際には機能しますが、プロジェクト全体のコンパイラオプションを実行するのではなく、['{$ WRITEABLECONST}'(http://docwiki.embarcadero.com/RADStudio/en/Writeable_typed_constants_(Delphi))ディレクティブが常に優先されます。すべて同じですが、アクティブな状態ですべての定数を静的および書き込み可能にするので、このオプションに少し疑念があります。 –

+0

書き込み可能な型付き定数では実行できないことは、その問題のコードで実行される初期化のタイプです。 –

関連する問題