web-dev-qa-db-ja.com

C ++におけるstaticキーワードとそのさまざまな用途

キーワードstaticはC++でいくつかの意味を持つもので、非常に混乱しやすいので、実際にどのように機能するのかについて考えを変えることはできません。

私が理解していることからstaticストレージ期間があります。これはグローバルの場合はプログラムの存続期間の間続くことを意味しますが、ローカルについて話しているときはデフォルトでゼロで初期化されることを意味します。

C++標準では、キーワードstaticを使用してクラスデータメンバに対してこれを示しています。

.7.1静的保存期間[basic.stc.static]

3キーワードstaticを使用して、静的記憶期間を持つローカル変数を宣言できます。

4クラス定義内のクラスデータメンバに適用されるキーワードstaticは、データメンバに静的格納期間を与えます。

ローカル変数とはどういう意味ですか?それは関数ローカル変数ですか?ローカル関数をstaticとしてローカルに宣言すると、その関数は1回しか初期化されないため、この関数に最初に入ったときにも発生します。

また、クラスメンバーに関するストレージの持続時間についてのみ説明しています。インスタンス固有ではないことについてはどうですか?それはstatic noのプロパティでもありますか?それとも保管期間ですか?

それではstaticとファイルスコープの場合はどうでしょうか。すべてのグローバル変数は、デフォルトで静的記憶期間を持つと見なされますか?次のように(セクション3.7.1から)そのことを示しているようです:

1動的記憶域期間を持たず、スレッド記憶域期間を持たず、ローカルではないであるすべての変数は静的記憶域期間を持ちます。これらの事業体の保管は、プログラムの期間中継続するものとします(3.6.2、3.6.3)。

staticは変数のリンケージとどのように関連していますか?

このstaticキーワード全体は実に混乱しやすいものですが、英語でのさまざまな使用方法を明確にし、またwhenstaticクラスメンバを初期化するように指示できますか?

167
Tony The Lion

変数:

static変数は、それが定義されている翻訳単位の「有効期間」に存在します。

  • 名前空間スコープ内にある場合(つまり、関数およびクラスの外部)、他の翻訳単位からアクセスすることはできません。これは、「内部リンケージ」または「静的ストレージ期間」として知られています。 (constexpr以外のヘッダーではこれを行わないでください。それ以外の場合、翻訳単位ごとに個別の変数が作成されることになり、混乱を招きます)
  • 変数関数内の場合、他のローカル変数と同様に、関数の外部からアクセスできません。 (これは彼らが言及したローカルです)
  • クラスメンバーには、staticによる制限付きスコープはありませんが、クラスおよびインスタンス(std::string::nposなど)からアドレス指定できます。 [注:declareクラス内の静的メンバーを使用できますが、通常は翻訳単位(cppファイル)内ではdefinedである必要があります。したがって、クラス]

コードとしての場所:

static std::string namespaceScope = "Hello";
void foo() {
    static std::string functionScope= "World";
}
struct A {
   static std::string classScope = "!";
};

変換ユニット内の関数が実行される前(おそらくmainが実行を開始した後)、その変換ユニット内の静的ストレージ期間(名前空間スコープ)を持つ変数は「定数初期化」(可能な場合はconstexprへ) 、またはゼロ)、非ローカルは適切に「動的に初期化」されます翻訳単位で定義されている順序でstd::string="HI";のようなconstexpr)。最後に、関数ローカルの静的変数は、実行が宣言された行に初めて「到達」したときに初期化されます。すべてのstatic変数は、初期化の逆の順序ですべて破棄されます。

このすべての権利を取得する最も簡単な方法は、constexpr以外のすべての静的変数を関数静的ローカルに初期化することです。これにより、使用するときに、したがって、 静的初期化順序fiasco を防止します。

T& get_global() {
    static T global = initial_value();
    return global;
}

注意してください、仕様が名前空間スコープ変数がデフォルトで「静的ストレージ期間」を持っていると言うとき、それらは「翻訳単位の寿命」ビットを意味しますが、それはnotはできないことを意味するのでファイルの外部からアクセスします。

関数

はるかに簡単なstaticは、多くの場合、クラスメンバー関数として使用され、独立した関数にはほとんど使用されません。

静的メンバー関数は、クラスのインスタンスなしで呼び出すことができ、インスタンスを持たないため、クラスの非静的メンバーにアクセスできないという点で、通常のメンバー関数とは異なります。静的変数は、インスタンスメンバを絶対に絶対に参照しないクラスの関数を使用する場合、またはstaticメンバ変数を管理する場合に役立ちます。

struct A {
    A() {++A_count;}
    A(const A&) {++A_count;}
    A(A&&) {++A_count;}
    ~A() {--A_count;}

    static int get_count() {return A_count;}
private:
    static int A_count;
}

int main() {
    A var;

    int c0 = var.get_count(); //some compilers give a warning, but it's ok.
    int c1 = A::get_count(); //normal way
}

static free-functionは、その関数が他の変換単位によって参照されないことを意味します。したがって、リンカーはそれを完全に無視できます。これにはいくつかの目的があります。

  • 関数が他のファイルから使用されないことを保証するためにcppファイルで使用できます。
  • ヘッダーに入れることができ、すべてのファイルに関数の独自のコピーがあります。インラインはほとんど同じことを行うため、有用ではありません。
  • 作業を減らすことでリンク時間を短縮します
  • 各翻訳単位に同じ名前の関数を配置でき、すべて異なる機能を実行できます。たとえば、各cppファイルにstatic void log(const char*) {}を配置し、それぞれが異なる方法でログに記録することができます。
127
Mooing Duck

静的記憶期間とは、プログラムの存続期間を通じて、変数がメモリ内の同じ場所に存在することを意味します。

リンケージはこれと直交しています。

これはあなたができる最も重要な区別だと思います。これを理解すること、そしてそれを覚えることは容易になるはずです(@Tonyに直接取り組むのではなく、将来これを読む人は誰でも) 。

キーワードstaticは内部リンケージand static storageを表すために使うことができますが、本質的にこれらは異なります。

ローカル変数とはどういう意味ですか?それは関数ローカル変数ですか?

はい。変数が初期化されるとき(関数への最初の呼び出し時および実行パスが宣言ポイントに達するとき)に関係なく、変数はプログラムの存続期間中メモリ内の同じ場所に存在します。この場合、staticは静的記憶域を提供します。

では、静的スコープとファイルスコープの場合はどうでしょうか。すべてのグローバル変数は、デフォルトで静的記憶期間を持つと見なされますか?

はい、すべてのグローバルは定義上静的な保存期間を持っています(これで意味が明確になりました)。 しかし名前空間スコープの変数はstaticで宣言されていません。これは内部リンケージを与えるので、翻訳単位あたりの変数です。

静的は変数のリンケージとどのように関連しますか。

名前空間スコープの変数に内部リンケージを与えます。それはメンバーとローカル変数に静的な保存期間を与えます。

これらすべてについて拡張しましょう。

//

static int x; //internal linkage
              //non-static storage - each translation unit will have its own copy of x
              //NOT A TRUE GLOBAL!

int y;        //static storage duration (can be used with extern)
              //actual global
              //external linkage
struct X
{
   static int x;     //static storage duration - shared between class instances 
};

void foo()
{
   static int x;     //static storage duration - shared between calls
}

この全体の静的キーワードは実に紛らわしいです

あなたがそれに精通していない限り、もちろんです。 :)言語に新しいキーワードを追加しないようにするために、委員会はこの効果、つまりIMOを再利用しました - 混乱。それは異なることを意味するのに使われます(私が言うかもしれませんが、おそらく反対のことです)。

63
Luchian Grigore

質問を明確にするために、「静的」キーワードの使用法を3つの異なる形式に分類します。

(A)。変数

(B)。関数

(C)。クラスのメンバー変数/関数

各サブ見出しについて以下に説明します。

(A)変数の「静的」キーワード

これは少し注意が必要ですが、適切に説明して理解すれば、非常に簡単です。

これを説明するには、まず、変数のスコープ、期間、およびリンケージを知ることが非常に役立ちます。静的キーワードの概念

1。 Scope:ファイル内のどこで変数にアクセスできるかを決定します。 (i)LocalまたはBlock Scopeの2種類があります。 (ii)グローバルスコープ

2。 Duration:変数がいつ作成および破棄されるかを決定します。繰り返しますが、2つのタイプがあります:(i)Automatic Storage Duration(LocalまたはBlockスコープを持つ変数の場合)。 (ii)Static Storage Duration(グローバルスコープを持つ変数またはローカル変数(関数内またはコードブロック内)でstatic指定子)。

3。 Linkage:別のファイルで変数にアクセス(またはリンク)できるかどうかを決定します。再び(幸運にも)2つのタイプがあります:(i)Internal Linkage(Block ScopeとGlobal Scope/File Scope/Global Namespace scopeを持つ変数の場合) )(ii)External Linkage(Global Scope/File Scope/Global Namespace Scopeのみを持つ変数の場合)

単純なグローバル変数とローカル変数の理解を深めるために、以下の例を参照してください(静的な保存期間を持つローカル変数はありません):

//main file
#include <iostream>

int global_var1; //has global scope
const global_var2(1.618); //has global scope

int main()
{
//these variables are local to the block main.
//they have automatic duration, i.e, they are created when the main() is 
//  executed and destroyed, when main goes out of scope
 int local_var1(23);
 const double local_var2(3.14);

 {
/* this is yet another block, all variables declared within this block are 
 have local scope limited within this block. */
// all variables declared within this block too have automatic duration, i.e, 
/*they are created at the point of definition within this block,
 and destroyed as soon as this block ends */
   char block_char1;
   int local_var1(32) //NOTE: this has been re-declared within the block, 
//it shadows the local_var1 declared outside

 std::cout << local_var1 <<"\n"; //prints 32

  }//end of block
  //local_var1 declared inside goes out of scope

 std::cout << local_var1 << "\n"; //prints 23

 global_var1 = 29; //global_var1 has been declared outside main (global scope)
 std::cout << global_var1 << "\n"; //prints 29
 std::cout << global_var2 << "\n"; //prints 1.618

 return 0;
}  //local_var1, local_var2 go out of scope as main ends
//global_var1, global_var2 go out of scope as the program terminates 
//(in this case program ends with end of main, so both local and global
//variable go out of scope together

リンケージの概念が登場しました。あるファイルで定義されたグローバル変数が別のファイルで使用されることを意図している場合、変数のリンケージが重要な役割を果たします。

グローバル変数のリンケージは、キーワードで指定されます:(i)static、および(ii)extern

(これで説明がわかります)

staticキーワードは、ローカルスコープとグローバルスコープの変数に適用できます。どちらの場合も、意味は異なります。最初に、グローバルスコープを持つ変数での 'static'キーワードの使用法を説明します(キーワード 'extern'の使用法も明確にします)。

1。グローバルスコープを持つ変数の静的キーワード

グローバル変数は静的な持続時間を持ちます。つまり、使用される特定のコードブロック(たとえばmain())が終了してもスコープ外になりません。リンケージに応じて、それらは宣言されている同じファイル内でのみアクセスできます(静的グローバル変数の場合)、または宣言されているファイルの外部でさえファイルの外部でアクセスできます(外部型グローバル変数)

Extern指定子を持つグローバル変数の場合、およびこの変数が初期化されたファイルの外部でアクセスされている場合、関数が前方にある必要があるように、使用されているファイルで前方宣言されなければなりません定義が使用されている場所とは異なるファイルにある場合に宣言されます。

対照的に、グローバル変数に静的キーワードがある場合、それが宣言されている外部のファイルでは使用できません。

(説明については以下の例を参照してください)

例えば:

//main2.cpp
 static int global_var3 = 23;  /*static global variable, cannot be                            
                                accessed in anyother file */
 extern double global_var4 = 71; /*can be accessed outside this file                  linked to main2.cpp */
 int main() { return 0; }

main3.cpp

//main3.cpp
#include <iostream>

int main()
{
   extern int gloabl_var4; /*this variable refers to the gloabal_var4
                            defined in the main2.cpp file */
  std::cout << global_var4 << "\n"; //prints 71;

  return 0;
}

現在、c ++の変数はconstまたはnon-constのいずれかであり、「const-ness」ごとに、何も指定されていない場合、デフォルトのc ++リンケージの2つのケースが取得されます。

(i)グローバル変数が非定数である場合、そのリンケージはデフォルトで外部にあります、つまり、非定数グローバル変数は別の場所でアクセスできますexternキーワードを使用した前方宣言による.cppファイル(つまり、const以外のグローバル変数には外部リンケージがあります(もちろん静的な期間))。また、定義されている元のファイルでのexternキーワードの使用は冗長です。この場合const以外のグローバル変数に外部ファイルからアクセスできないようにするには、変数のタイプの前に指定子 'static'を使用します

(ii)グローバル変数がconstの場合、そのリンケージはデフォルトで静的です。つまり、constグローバル変数はそれ以外のファイルではアクセスできませんが定義されています(言い換えると、constグローバル変数には内部リンクがあります(もちろん、静的な期間))。また、constグローバル変数が別のファイルでアクセスされるのを防ぐためのstaticキーワードの使用は冗長です。ここで、constグローバル変数に外部リンケージを持たせるには、変数のタイプの前に指定子 'extern'を使用します

さまざまなリンケージを持つグローバルスコープ変数の概要を以下に示します

//globalVariables1.cpp 

// defining uninitialized vairbles
int globalVar1; //  uninitialized global variable with external linkage 
static int globalVar2; // uninitialized global variable with internal linkage
const int globalVar3; // error, since const variables must be initialized upon declaration
const int globalVar4 = 23; //correct, but with static linkage (cannot be accessed outside the file where it has been declared*/
extern const double globalVar5 = 1.57; //this const variable ca be accessed outside the file where it has been declared

次に、別のファイルでアクセスした場合に上記のグローバル変数がどのように動作するかを調査します。

//using_globalVariables1.cpp (eg for the usage of global variables above)

// Forward declaration via extern keyword:
 extern int globalVar1; // correct since globalVar1 is not a const or static
 extern int globalVar2; //incorrect since globalVar2 has internal linkage
 extern const int globalVar4; /* incorrect since globalVar4 has no extern 
                         specifier, limited to internal linkage by
                         default (static specifier for const variables) */
 extern const double globalVar5; /*correct since in the previous file, it 
                           has extern specifier, no need to initialize the
                       const variable here, since it has already been
                       legitimately defined perviously */

2.ローカルスコープを持つ変数の静的キーワード

ローカルスコープ内の変数の静的キーワードの更新(2019年8月)

これは、さらに2つのカテゴリに分類できます。

(i)関数ブロック内の変数の静的キーワード、および(ii)無名の変数内の静的キーワードローカルブロック

(i)関数ブロック内の変数の静的キーワード。

先ほど、ローカルスコープの変数は自動継続期間を持っている、つまり、ブロックに入ると(通常のブロックでも、関数ブロックでも)存在し、ブロックが終了すると存在しなくなり、長いストーリーローカルスコープの変数には自動期間がありますおよび自動期間変数(およびオブジェクト)にはリンケージがないため、コードの外部からは見えません。ブロック。

static指定子が関数ブロック内のローカル変数に適用されると、変数の期間が自動から変更されます staticであり、その有効期間はプログラムの全期間です。つまり、メモリの場所が固定されており、その値は cpp参照 (初期化と割り当てを混同しないでください)

例を見てみましょう。

//localVarDemo1.cpp    
 int localNextID()
{
  int tempID = 1;  //tempID created here
  return tempID++; //copy of tempID returned and tempID incremented to 2
} //tempID destroyed here, hence value of tempID lost

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here :-)


int main()
{
  int employeeID1 = localNextID();  //employeeID1 = 1
  int employeeID2 = localNextID();  // employeeID2 = 1 again (not desired)
  int employeeID3 = newNextID(); //employeeID3 = 0;
  int employeeID4 = newNextID(); //employeeID4 = 1;
  int employeeID5 = newNextID(); //employeeID5 = 2;
  return 0;
}

静的なローカル変数と静的なグローバル変数の上記の基準を見ると、それらの違いは何であるかを尋ねたいと思うかもしれません。グローバル変数はコード内の任意の時点でアクセス可能ですが(const-nessおよびextern-ness)、関数ブロック内で定義された静的変数は直接アクセスできません。変数は、関数の値または参照によって返される必要があります。例でこれを示しましょう:

//localVarDemo2.cpp 

//static storage duration with global scope 
//note this variable can be accessed from outside the file
//in a different compilation unit by using `extern` specifier
//which might not be desirable for certain use case.
static int globalId = 0;

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here


int main()
{
    //since globalId is accessible we use it directly
  const int globalEmployee1Id = globalId++; //globalEmployeeId1 = 0;
  const int globalEmployee2Id = globalId++; //globalEmployeeId1 = 1;

  //const int employeeID1 = newID++; //this will lead to compilation error since newID++ is not accessible direcly. 
  int employeeID2 = newNextID(); //employeeID3 = 0;
  int employeeID2 = newNextID(); //employeeID3 = 1;

  return 0;
}

静的なグローバル変数と静的なローカル変数の選択に関する詳細な説明は、 this stackoverflow thread

(ii)名前のないローカルブロック内の変数の静的キーワード。

ローカルブロックがスコープ外になると、ローカルブロック(関数ブロックではない)内の静的変数にブロック外からアクセスすることはできません。このルールには注意事項はありません。

    //localVarDemo3.cpp 
    int main()
    {

      {
          const static int static_local_scoped_variable {99};
      }//static_local_scoped_variable goes out of scope

      //the line below causes compilation error
      //do_something is an arbitrary function
      do_something(static_local_scoped_variable);
      return 0;
    }

C++ 11はキーワードconstexprを導入しました。これは、コンパイル時に式の評価を保証し、コンパイラーがコードを最適化できるようにします。現在、スコープ内の静的const変数の値がコンパイル時にわかっている場合、コードはconstexprを使用した場合と同様の方法で最適化されます。 これは小さな例です

this stackoverflow thread の変数について、constexprstatic constの違いを調べることもお勧めします。これで、変数に適用される静的キーワードについての私の説明は終わりです。

B。関数に使用される 'static'キーワード

関数の観点では、staticキーワードには簡単な意味があります。ここでは、は関数のリンケージを指します通常、cppファイル内で宣言されたすべての関数はデフォルトで外部リンケージを持ちます。つまり、1つのファイルで定義された関数はforward宣言によって別のcppファイルで使用されます。

関数宣言がそのリンケージをinternalに制限する前に静的キーワードを使用します。つまり、静的関数は定義外のファイル内では使用できません。

C。クラスのメンバー変数および関数に使用されるStaitcキーワード

1。クラスのメンバー変数の 'static'キーワード

ここから例から直接始めます

#include <iostream>

class DesignNumber
{
  private:

      static int m_designNum;  //design number
      int m_iteration;     // number of iterations performed for the design

  public:
    DesignNumber() {     }  //default constructor

   int  getItrNum() //get the iteration number of design
   {
      m_iteration = m_designNum++;
      return m_iteration;
   }
     static int m_anyNumber;  //public static variable
};
int DesignNumber::m_designNum = 0; // starting with design id = 0
                     // note : no need of static keyword here
                     //causes compiler error if static keyword used
int DesignNumber::m_anyNumber = 99; /* initialization of inclass public 
                                    static member  */
enter code here

int main()
{
   DesignNumber firstDesign, secondDesign, thirdDesign;
   std::cout << firstDesign.getItrNum() << "\n";  //prints 0
   std::cout << secondDesign.getItrNum() << "\n"; //prints 1
   std::cout << thirdDesign.getItrNum() << "\n";  //prints 2

   std::cout << DesignNumber::m_anyNumber++ << "\n";  /* no object
                                        associated with m_anyNumber */
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 100
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 101

   return 0;
}

この例では、静的変数m_designNumはその値を保持し、この単一のプライベートメンバー変数(静的であるため)は、オブジェクトタイプDesignNumberのすべての変数で共有されます。

また、他のメンバー変数と同様に、クラスの静的メンバー変数はどのクラスオブジェクトにも関連付けられていません。これは、main関数でanyNumberを出力することで実証されます

クラス内の定数と非定数の静的メンバー変数

(i)非constクラスの静的メンバー変数前の例では、静的メンバー(パブリックとプライベートの両方)は非定数でした。 ISO標準では、非const静的メンバーをクラスで初期化することを禁止しています。したがって、前の例のように、クラス定義の後に初期化する必要がありますが、静的キーワードを省略する必要があるという警告があります

(ii)クラスのconst-staticメンバー変数これは簡単で、他のconstメンバー変数の初期化の規則、つまり、const staticメンバー変数のクラスcan be宣言の時点で初期化され、クラス宣言の最後に初期化できます。クラスの後に初期化する場合、キーワードconstを静的メンバーに追加する必要があるという1つの注意事項があります。定義。

ただし、宣言の時点でconst静的メンバー変数を初期化することをお勧めします。これは標準のC++規約に準拠しており、コードがよりきれいに見えます。

クラス内の静的メンバー変数のその他の例については、learncpp.comから次のリンクを参照してください http://www.learncpp.com/cpp-tutorial/811-static-member-variables/

2。クラスのメンバー関数の 'static'キーワード

クラスのメンバー変数が静的であるように、クラスのメンバー関数も同様です。クラスの通常のメンバー関数は、常にクラスタイプのオブジェクトに関連付けられます。対照的に、クラスの静的メンバー関数はクラスのどのオブジェクトにも関連付けられていません。つまり、* thisポインターはありません。

第二に、クラスの静的メンバー関数には* thisポインターがないため、メイン関数でクラス名とスコープ解決演算子を使用して呼び出すことができます(ClassName :: functionName();)

3番目に、クラスの静的メンバー関数は、クラスの静的メンバー変数にのみアクセスできます。これは、クラスの非静的メンバー変数がクラスオブジェクトに属している必要があるためです。

クラス内の静的メンバー関数のその他の例については、learncpp.comから次のリンクを参照してください。

http://www.learncpp.com/cpp-tutorial/812-static-member-functions/

22
ggulgulia

実はとても簡単です。関数のスコープ内で変数を静的として宣言した場合、その値はその関数への連続した呼び出しの間で保持されます。そう:

int myFun()
{
static int i=5;
i++;
return i;
}
int main()
{
printf("%d", myFun());
printf("%d", myFun());
printf("%d", myFun());
}

増分された値を記憶しているため、678の代わりに666を表示します。

静的メンバーに関しては、それらはクラスのインスタンス間で値を保持します。だから、次のコード:

struct A
{
static int a;
};
int main()
{
A first;
A second;
first.a = 3;
second.a = 4;
printf("%d", first.a);
}

first.aとsecond.aは基本的に同じ変数なので、4が表示されます。初期化に関しては、 この質問を参照してください。

19

ファイルスコープでstatic変数を宣言すると、その変数はthat特定のファイルでのみ使用可能になります(厳密には* translation unitですが、これをあまり複雑にしないでください)。例えば:

a.cpp

static int x = 7;

void printax()
{
    cout << "from a.cpp: x=" << x << endl;
}

b.cpp

static int x = 9;

void printbx()
{
    cout << "from b.cpp: x=" << x << endl;
}

main.cpp:

int main(int, char **)
{
    printax(); // Will print 7
    printbx(); // Will print 9

    return 0;
}

local変数の場合、staticは、変数がゼロで初期化されることを意味しますandは、呼び出し間でその値を保持します。

unsigned int powersoftwo()
{
    static unsigned lastpow;

    if(lastpow == 0)
        lastpow = 1;
    else
        lastpow *= 2;

    return lastpow;
}

int main(int, char **)
{
    for(int i = 0; i != 10; i++)
        cout << "2^" << i << " = " << powersoftwo() << endl;
}

class変数の場合、そのクラスのすべてのメンバー間で共有されるその変数のインスタンスは1つだけです。許可に応じて、変数はその完全修飾名を使用してクラスの外部からアクセスできます。

class Test
{
private:
    static char *xxx;

public:
    static int yyy;

public:
    Test()
    {        
        cout << this << "The static class variable xxx is at address "
             << static_cast<void *>(xxx) << endl;
        cout << this << "The static class variable yyy is at address "
             << static_cast<void *>(&y) << endl;
    }
};

// Necessary for static class variables.
char *Test::xxx = "I'm Triple X!";
int Test::yyy = 0;

int main(int, char **)
{
    Test t1;
    Test t2;

    Test::yyy = 666;

    Test t3;
};

クラス以外の関数をstaticとしてマークすると、そのファイルからのみアクセス可能になり、他のファイルからはアクセス不能になります。

a.cpp

static void printfilename()
{ // this is the printfilename from a.cpp - 
  // it can't be accessed from any other file
    cout << "this is a.cpp" << endl;
}

b.cpp

static void printfilename()
{ // this is the printfilename from b.cpp - 
  // it can't be accessed from any other file
    cout << "this is b.cpp" << endl;
}

クラスメンバ関数のために、それらをstaticとしてマークすることは、その関数がオブジェクトの特定のインスタンスの上で呼ばれる必要がないことを意味します(すなわち、それはthisポインタを持ちません)。

class Test
{
private:
    static int count;

public:
    static int GetTestCount()
    {
        return count;
    };

    Test()
    {
        cout << this << "Created an instance of Test" << endl;
        count++;
    }

    ~Test()
    {
        cout << this << "Destroyed an instance of Test" << endl;
        count--;
    }
};

int Test::count = 0;

int main(int, char **)
{
    Test *arr[10] = { NULL };

    for(int i = 0; i != 10; i++)
        arr[i] = new Test();

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    // now, delete them all except the first and last!
    for(int i = 1; i != 9; i++)
        delete arr[i];        

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[0];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[9];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    return 0;
}
8
Nik Bougalis

静的変数は、各クラスが独自の変数を持つのではなく、クラスのすべてのインスタンス間で共有されます。

class MyClass
{
    public:
    int myVar; 
    static int myStaticVar;
};

//Static member variables must be initialized. Unless you're using C++11, or it's an integer type,
//they have to be defined and initialized outside of the class like this:
MyClass::myStaticVar = 0;

MyClass classA;
MyClass classB;

'MyClass'の各インスタンスはそれぞれ独自の 'my​​Var'を持ちますが、同じ 'myStaticVar'を共有します。実際には、 'myStaticVar'にアクセスするためにMyClassのインスタンスさえ必要としません。また、このようにクラスの外部でアクセスすることもできます。

MyClass::myStaticVar //Assuming it's publicly accessible.

関数内でローカル変数として(クラスのメンバ変数としてではなく)使用されると、staticキーワードは別の動作をします。グローバルスコープを指定せずに、永続変数を作成できます。

int myFunc()
{
   int myVar = 0; //Each time the code reaches here, a new variable called 'myVar' is initialized.
   myVar++;

   //Given the above code, this will *always* print '1'.
   std::cout << myVar << std::endl;

   //The first time the code reaches here, 'myStaticVar' is initialized. But ONLY the first time.
   static int myStaticVar = 0;

   //Each time the code reaches here, myStaticVar is incremented.
   myStaticVar++;

   //This will print a continuously incrementing number,
   //each time the function is called. '1', '2', '3', etc...
   std::cout << myStaticVar << std::endl;
}

これは永続性の点ではグローバル変数ですが、スコープ/アクセシビリティの点でグローバルではありません。

静的メンバー関数を持つこともできます。静的関数は基本的にはメンバではない関数ですが、クラス名の名前空間の中にあり、クラスのメンバへのプライベートアクセスを持ちます。

class MyClass
{
    public:
    int Func()
    {
        //...do something...
    }

    static int StaticFunc()
    {
        //...do something...
    }
};

int main()
{
   MyClass myClassA;
   myClassA.Func(); //Calls 'Func'.
   myClassA.StaticFunc(); //Calls 'StaticFunc'.

   MyClass::StaticFunc(); //Calls 'StaticFunc'.
   MyClass::Func(); //Error: You can't call a non-static member-function without a class instance!

   return 0;
}

メンバ関数を呼び出すとき、 'this'という隠しパラメータがあります。これは、関数を呼び出すクラスのインスタンスへのポインタです。静的メンバー関数しない隠しパラメータを持っています...クラスインスタンスなしで呼び出すことができますが、クラスの非静的メンバー変数にアクセスすることもできません。 '作業へのポインタ。特定のクラスインスタンスでは呼び出されていません。

8
Jamin Grey

ローカル変数とはどういう意味ですか?それは関数ローカル変数ですか?

Yes - 関数ローカル変数などの非グローバル.

関数をローカルとしてstaticとして宣言したときに一度だけ初期化されるということもあるので、それがこの関数に最初に入ったときです。

右。

また、クラスメンバーに関するストレージの持続時間についてのみ説明しています。インスタンス固有ではないことについても説明します。これはstatic noのプロパティでもありますか。それとも保管期間ですか?

class R { static int a; }; // << static lives for the duration of the program

つまり、Rのすべてのインスタンスがint R::a - int R::aを共有することは決してコピーされません。

では、静的スコープとファイルスコープの場合はどうでしょうか。

事実上、適切な場合にコンストラクタ/デストラクタを持つグローバル - 初期化はアクセスまで延期されません。

静的は変数のリンケージとどのように関連しますか。

ローカル関数の場合は外部です。アクセス:関数からアクセス可能です(もちろん、あなたがそれを返さない限り)。

クラスにとっては、それは外部的なものです。アクセス:標準のアクセス指定子(パブリック、保護、プライベート)が適用されます。

staticは、宣言されている場所(ファイル/名前空間)によっては、内部リンケージも指定できます。

この全体の静的キーワードは実に紛らわしいです

C++では目的が多すぎます。

誰かがその英語のさまざまな使用法を明確にし、静的クラスメンバーを初期化するタイミングを教えてもらえますか?

ロードされていてコンストラクターがある場合は、自動的にmainの前に初期化されます。それは良いことのように思えるかもしれませんが、初期化の順序はあなたのコントロールをはるかに超えているので、複雑な初期化は維持するのが非常に困難になります。プロジェクト静的な保存期間を持つデータに関しては、特に可変(グローバル変数)の場合は、この設計を最小限に抑えるようにしてください。初期化の「時間」もさまざまな理由で異なります。ローダーとカーネルには、メモリ使用量を最小限に抑え、問題のデータに応じて初期化を遅らせるためのトリックがあります。

1
justin

私はCプログラマーではないので、Cプログラムでのstaticの使い方について適切に情報を提供することはできませんが、オブジェクト指向プログラミングに関しては、staticは基本的に変数、関数またはクラスを同じと宣言します。プログラムの生涯を通して。例を挙げましょう。

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
private:
    void somePrivateMethod();
};

メインでこのクラスをインスタンス化すると、次のようになります。

int main()
{
   A a1;
   //do something on a1
   A a2;
   //do something on a2
}

これら2つのクラスインスタンスは互いに完全に異なり、互いに独立して動作します。しかし、もしあなたがこのようにクラスAを作り直すならば。

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
    static int x;
private:
    void somePrivateMethod();
};

再びメインに戻りましょう。

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   A a2;
   a2.x++;
   //do something on a2
}

その場合、a1とa2はint xの同じコピーを共有し、それによってa1内のxに対する演算はすべて、a2内のxの演算に直接影響を与えます。だから私はこれをやろうとしていた場合

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   cout << a1.x << endl; //this would be 1
   A a2;
   a2.x++;
   cout << a2.x << endl; //this would be 2 
   //do something on a2
}

クラスAの両方のインスタンスは、静的変数と関数を共有します。これがあなたの質問に答えることを願っています。 Cについての私の知識が限られているので、関数や変数をstaticとして定義することは、その関数や変数がstaticとして定義されていることがファイルからしか見えないことを意味します。 C++では、Cと完全に後方互換性があるため、CとC++の両方の方法で変数を静的変数として宣言できます。

1
David Tr

Static Object: staticキーワードを使ってクラスメンバをstaticに定義することができます。クラスのメンバをstaticとして宣言すると、そのクラスのオブジェクトがいくつ作成されても、静的メンバのコピーは1つだけになります。

静的メンバーはクラスのすべてのオブジェクトによって共有されます。他の初期化が存在しない場合、最初のオブジェクトが作成されると、すべての静的データはゼロに初期化されます。クラス定義に入れることはできませんが、次の例のように、スコープ解決operator ::を使用して静的変数を再宣言することで、クラスの外部で初期化できます。

次の例を試して、静的データメンバの概念を理解しましょう。

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{
   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects.
   cout << "Total objects: " << Box::objectCount << endl;

   return 0;
}

上記のコードをコンパイルして実行すると、次のような結果が得られます。

Constructor called.
Constructor called.
Total objects: 2

静的関数メンバー関数メンバーを静的として宣言することで、クラスの特定のオブジェクトから独立させることができます。クラスのオブジェクトが存在せず、クラス名とスコープ解決演算子::のみを使用して静的関数にアクセスする場合でも、静的メンバー関数を呼び出すことができます。

静的メンバー関数は、クラス外から静的データメンバー、他の静的メンバー関数、その他の関数にのみアクセスできます。

静的メンバー関数はクラススコープを持ち、それらはクラスのthisポインタにアクセスできません。静的メンバー関数を使用して、クラスのいくつかのオブジェクトが作成されたかどうかを判断できます。

次の例を試して、静的関数メンバーの概念を理解しましょう。

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
      static int getCount()
      {
         return objectCount;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{

   // Print total number of objects before creating object.
   cout << "Inital Stage Count: " << Box::getCount() << endl;

   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects after creating object.
   cout << "Final Stage Count: " << Box::getCount() << endl;

   return 0;
}

上記のコードをコンパイルして実行すると、次のような結果が得られます。

Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2
1
Nima Soroush