2012-07-13 5 views
5

私は、名前空間や静的変数の根本的な誤解と思います。 main.cppに名前空間で変数を扱う方法

namespace test{ 
    static int testNum=5; 
    void setNum(int value); 
} 

:私はこれを実行すると

#include <test.h> 

int test::setNum(int value){ 
    testNum=value; 
} 

int main(){ 
    test::setNum(9); 
    cout<<test::testNum; 
} 

私は値5を得る。しかし、私はこのテストコード(手作業で入力されたが、タイプミスを許して)

TEST.Hを試してみました私が期待したように9ではない。私はtestNum変数の2つのインスタンスを持っているかのように見えますが、それは静的とは正反対のようです。私は、これらの機能がJava Equilibantと何らかの形で同じであると仮定して間違いを犯したと推測しています...

私の宣言から静的を削除すると、testNumが複数回宣言されているというエラーが表示されます。 testNum、誰かがそれがなぜ同じ理由であるか説明することができますか?

は、名前空間スコープで

+1

'#include'の仕組みを知っていますか?指定されたファイルの内容をコピー&ペーストします。そして 'setNum'定義は本当に' main.cpp'にもありますか? – Xeo

+0

私はそれを示していませんでしたが、私は標準のifNDEF DEFを私の.hに持っています。また、私はプログラム全体に* once *を含めるだけなので、それでも問題はないでしょうか? – dsollen

+0

'using namespace test'を使用していますか? –

答えて

14

まず、あなたの誤解はでなければ何もありません。は名前空間と関係ありません。それは約staticです。この回答の残りの部分については、簡単にtestNumを参照するつもりです。なぜなら、名前空間内にあるという事実は無関係であるからです。

私はまたtest.hを含み、setNum機能を定義している、おそらくtest.cppと呼ばれる別のファイルがあるとします。

名前空間スコープの変数または関数(つまり、関数のクラスメンバーでもローカルでもない)がstaticと宣言されている場合、エンティティの名前はそのファイルの内部にあることを意味します。正式には、それは名前で参照することも、他のファイルからリンクすることもできない(ポインタで間接的に参照することも、別の関数の引数として渡すこともできます)ことを意味する「内部リンケージ」を持ちます。つまり、ファイルにはstatic int testNumが定義されており、各ファイルには他のすべてのファイルのtestNumとは別の名前の内部変数があります(実際には1つのファイルにはstatic int testnum、もう1つにはstatic double testnum、別のファイルにはstatic char* testNum)ファイル)。ヘッダーにそのような定義を入れると、ヘッダーを含むすべてのファイルには独自のものがありますtestNum。あなたがtest.hが含まれ、すべてのファイルにtestNum呼ば異なる変数を持っているヘッダーであなたの変数にstaticとそう

。つまり、testNumを1つのファイルに設定し、testNumを使用する別のファイルの関数を呼び出すと、という異なるという変数が参照されます。この変数は同じ名前になります。

このため、非const staticという変数をヘッダーに宣言することは、ほとんど常に間違っています。すべてのエンティティは、一度定義し、一度だけ、あなたのプログラムでなければなりません:

staticがなければ、あなたが許可されていないtest.hを含み、すべてのファイルにtestNum変数の定義を持っているでしょう。それを解決する方法はヘッダで変数を宣言することですが、ない変数がexternあるコンパイラを伝えることで、あなたがこれ、にそれを定義します。

コンパイラに指示します
extern int testNum; // N.B. no "= 1" here 

は変数がありますtestNumと呼ばれる「外部リンケージ」を使用しているので、コードがtestNumを指しているときは、常に同じ変数を意味します(内部ファイル内の異なるエンティティは内部ファイルではありません)。extern変数を宣言した後、プログラムのどこかで提供されている1つの定義だけであるため、では正確にファイル(すなわち、

int testNum = 1; 
+0

ありがとう、それは私の問題を説明します。私が思うように、静的な方法を私のJava開発からどうやって行ったのか間違った仮定をしていると思っていましたが、静的なものを最初に調べて、C++の静的なものと同じものを考えました。実際のプログラムでは、たとえ誰かが行ってmain.hを変更しても、静的な値を何か安全なものにすることが本当に好きです。あたかもexternが有効なデフォルト値で始まるということを私が妨げるかのように思えます。それを保証する方法はありますか? – dsollen

+0

'static'はC++のいくつかのことを意味します。 _classメンバの場合はJavaに似ていますが、プログラムにクラスメンバはありません。Javaには存在しない非メンバグローバルがあります。 –

+0

externが「デフォルト」の値を防止しているか、「何かを安全にする」ということが何を意味するのか分かりません。私の答えで与えた '= 1 'の値に何が問題なのですか? –

3

staticは誤った名称であり、使用すべきではありません、ありがとうございました。 は、単に静的と宣言されたエンティティに内部的な名前バインディングがあることを意味します。 つまり、他の翻訳単位の同じ名前は を別のエンティティに参照し、変数定義の場合は の各翻訳に別々のインスタンスが存在します。 単位。それは生涯に影響しません。 (名前空間スコープで定義されたすべての宣言された変数や は静的な寿命を持っている。)

static名前空間スコープでも推奨されていません。それを使用しないでください。

ヘッダーに変数を宣言する場合は、 externという接頭辞を付け、staticではなく接頭辞を付けます。変数がexternと宣言され、 に初期化がない場合、宣言は定義ではありません。 のうち、この場合は、どこかで定義を提供する必要があります( 単一ソースファイル内)。 、静的

  • オブジェクトは寿命があります(オート:

    extern int testNum = 5; 
    int testNum = 5; 
    int testNum;   // implicitly initialized with 0. 
    

    EDIT:

    がやや明確にする:いくつかの混乱が寿命と結合 名の間ここにありの線に沿って何かまたは動的—または一時的な、または例外)、および

  • 名前はエンティティにバインドされています。名前が変数であると宣言されている場合、エンティティはオブジェクトです。

は、静的な生涯とキーワードstaticを混同しないを行います。 (機能 はstaticすることができますが、機能はC++で何も定義された寿命を持っていない。彼らはただそこに です。)これらに関する

ルールは非常にorthognalではありません。基本的には、一生に に関して:

  • 名前空間スコープで宣言されたすべての変数は常に、静的な寿命を持つ、ローカルスコープで宣言
  • の変数は、それらがstatic宣言されているない限り、自動寿命を持っている、と
  • 変数staticと宣言されていない限り、クラススコープで宣言されたクラスオブジェクトは、それらを含むクラスオブジェクトの存続期間を持ちます。生涯については とします。静的寿命と

オブジェクトがmain前にいつかされて入って来て、あなたがmainから戻った後まで ライブ。

名に関しては、結合して:彼らはstatic宣言されない限り、名前空間スコープで宣言

  • 変数は、結合外部名、 を持っている彼らは、結合の内部 名前を持っている(ただし、staticのこの使用は推奨されている場合には)、または、彼らは constであり、宣言されていないクラススコープで宣言extern
  • 変数は、それらがstatic宣言されている場合でも、バインディング外部名を持ち、かつ
  • 場合
  • ブロックスコープで宣言された変数にはバインディングがありません。

最後に、宣言が定義 であるかどうかという疑問があります。定義の場合、メモリが割り当てられ、オブジェクトは (または初期化されている可能性があります)です。定義でない場合は、宣言で宣言されているエンティティ (オブジェクト)の別の場所に定義があることをコンパイラに通知します( )。一般に、変数 の宣言は、と宣言されていない限り、の定義であり、と宣言され、 ではありません。にはイニシャライザがあります。あなたは間違って何を求め、それを投稿する前に、あなたのコードは、実際に問題を抱えていることを確認したい場合があります

+0

解決していただきありがとうございます(私は1秒後にそれを試してみる)が、私自身の啓発のために、問題の内容をよりよく説明できますか?あなたは名前空間内のすべての変数は静的であると言っていますが、私には静的変数だけが必要なので、この例では私のコードがうまくいかない理由がわかりません。私はtestnumを参照しているそれぞれの場所で同じ名前の2つの静的変数を宣言することになりましたか? – dsollen

+0

@dsollen私はいくつかの説明を追加するように編集しました。 –

1

;)

私が貼り付けられた/コピーし、タイプミスを修正して、手動でインクルードが含まれた:

#include <iostream> 
using namespace std; 

namespace test{ 
    static int testNum=5; 
    void setNum(int value); 
} 

void test::setNum(int value){ 
    testNum=value; 
} 

int main(){ 
    test::setNum(9); 
    cout<<test::testNum; 
} 

結果:

$ ./a.out 
9 

あなたのプログラムには他に何があるのですか? main.cpp以上のものがあり、test.hをインクルードしている場合は、各.cppファイルにtestNumという独自のコピーがあります。あなたがそれらを共有したい場合は、externとマークするために1つ以外のものすべてが必要です。

関連する問題