C++クラスのstaticの違い

このQ&Aのポイント
  • (1)クラスのメンバー変数にstaticを付けた場合と、メンバーではない変数にstaticを付けた場合の違いは何ですか?
  • (2)クラスのメンバー関数にstaticを付けた場合と、メンバーではない関数にstaticを付けた場合の違いは何ですか?
  • C++のクラスにおけるstaticの使い方について理解したいです。
回答を見る
  • ベストアンサー

C++ クラス概念

以下の違いがよく理解できていません。 どなたかご教授お願い致します。 (1)クラスのメンバー変数に static を付けた場合と、 メンバーではない変数に static を付けた場合の違い (2)クラスのメンバー関数に static を付けた場合と、 メンバーではない関数に static を付けた場合の違い [プログラム例] class MyClass { public: static int internalCount; static void func(MyClass& a) {/* ... */} }; static int i; static void f(MyClass& a) { /* ... */ }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

3)クラスにおける static これは、アクセス制御ではなく、「クラスのインスタンス全体での共有」を行うためのもです。 アクセス制御ではないので、static をつけただけで、クラスの外からでも参照できると言うことはありません。 あくまでも、宣言された位置が、public: か、private: か、proteced: かで、どの範囲から参照できるかが決まります。 さて、クラスというのは、通常、インスタンスを生成して使用します。 class CAT; に対して、 CAT tama("nya"); CAT buchi("myamya"); とか。 こことで(正しく設計されていれば) tama が、buchi の泣き方を知ることはありません。 これが、「情報の隠蔽」という機能で、クラスの利点のひとつにもなっています。 一方で、これだけでは、たとえば、「では、CAT は何匹存在するのだろうか?」という情報を得ることはできません。 tama にしても、buchi にしても、自分自身の情報は知っていますが、CAT というクラス全体の情報は何も知らないからです。 これを解決するために使うのが、class における static 指定です。 class CAT { private: char *myNakigoe; static int number; public: CAT(char *nakigoe) : myNakigoe(nakigoe) { numer ++; } ~CAT() { number--;} // このmyNakigoe の初期化は、本当はちょっと危険 }; などとしておけば、クラスの中から、CAT::number を参照すれば、現存する猫の数がわかります。 メンバ関数に対する static 指定も同じで、「クラス全体の情報を知る/操作する」ための関数は、static をつけて指定します。 たとえば、 static void defaultNakigoe(char *); などで、泣き方を指定しない猫たち全部のデフォルトの鳴き声を指定できたりします。 この場合、あくまでも、鳴き声を指定しない猫たち「全部」なので、個別の猫の情報には直接タッチしないことに注意してください。 ただ、static なメンバ関数から、個々のインスタンスの情報が絶対にアクセスできないというわけではありません。 static char *nakigoe(CAT *dare) { return dare->myNakigoe; } などと言うこともできなくはありません。

rdxs41
質問者

お礼

ありがとうございます。 何が違うのかはっきりしてすっきりしました。

その他の回答 (2)

回答No.2

static という予約後は、実は、いろいろな意味に使い回されています。 これがそもそも混乱の元になっているわけですが、クラスに関連するもの、しないものをふくめて、こういう意味があります。 1)関数の(ブロックの)中で定義される変数。 void count() { int n = 0; n++; std::cout << "cout = " << n << "\n"; } この関数は、何度呼び出しても、毎回 count = 0 を表示します。 これは、n という変数が、関数の呼び出しごとに生成・初期化されるからです。 一方、 void count() { static int n = 0; n++; std::cout << "cout = " << n << "\n"; } とすると、この関数は、呼び出された回数を表示するようになります。 static をつけたことで、n が、「プログラムの実行の最初に生成・初期化されて、その変数が消えずに残る」からです。 この場合、最初の(static をつけない)変数は、auto int n = 0; と書きますが、特に断りがない限りCの変数は auto なので、auto が明示されることはほぼありません。 ※ただし、 static int n = 0; と書けば「初期化」なので、プログラム実行時に1回しか初期化されませんが、 static int n; n = 0; と書けば、 n = 0; は、当然、関数の呼び出しごとに実行されてしまいます。 2)ブロックの外の変数および、関数 これは、 int n; int main() { .... } のように、(main を含む)関数の外に定義される変数です。 1)で、「static をつけると、プログラム実行時に1度だけ初期化され、その変数が消えずに残る」と書きましたが、ブロックの外にある変数はもともと、「プログラム実行中消えずに残る」ものです。 ですから、ブロックの中にある static とは意味が違います。 こちらは、「アクセス制御」のためのものです。 ブロックの外にある変数は、「グローバル変数」と呼ばれ、そのファイルの中にある関数で共有されます。 それだけではなく、別のファイルの中にある関数とも共有されてしまいます。 もともと「変数の共有」というのはできるだけ避けるべきです。 それは、あちこちで共有されてしまえば、何かおかしな事が起こったときに、どこでおかしな事になったのか、突き止めるのが大変だからです。 そのため、「同じファイルの中の各関数では共有したいけど、このファイルの中だけの共有に抑えたい」という要求があります。 これを実現するのが、ブロックの外にある変数での static 指定です。 static int n; int main() { .... } こうすれば、この n は、この他のファイルからは参照できなくなります。 ブロックの外にある「関数」も、static をつける意味は同じです。 このファイルの中からしか参照できないようにするには、 static void func(); のように、static をつけます。 関数の場合、もともと共有するものという性格が強いのですが、「他のファイルから参照できない」ということを保証することで、関数の仕様変更を行う際、「そのファイルの中での使われ方」だけを考えれば良いという効果があります。 ここであげた、「ブロックの外のstatic」は、アクセス制御に関わるものですから、C++であれば、クラスや、name space を使う事で、目的を果たすこともできます。 しかし、C言語で、「クラスもname space もない」という状況で導入されたまま、互換性維持のためにそのまま残っているわけです。 3)クラス定義における static …… 続く。

  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.1

簡単な解説をすると以下のようになります。 [プログラム例] class MyClass { public: static int internalCount; ・・・(1) static void func(MyClass& a) {/* ... */} ・・・(2) }; static int i; ・・・(3) static void f(MyClass& a) ・・・(4) { /* ... */ } (1)クラス内のstatic変数:クラス変数という(staticをつけない変数はインスタンス変数という)。MyClassクラスのインスタンス全てで共有される変数。MyClass::internalCount = 0という風に(publicなので)クラス外からのアクセスも可能。 (2)クラス内のstatic関数:MyClassのインスタンス->func()ではなく、MyClass::func()という風にインスタンスを作らなくても呼び出せる関数。クラス変数にはアクセスできるがインスタンス変数にはアクセスできない。 (3)クラス外のstatic変数:C言語のstaticと同じ。これ以外のソースファイル中にextern int i;宣言があってもこの変数はこのソースファイル固有。 (4)クラス外のstatic関数:C言語のstaticと同じ。これ以外のソースファイル中でf()を呼び出そうとしても呼び出せない。 (3)と(4)はC言語の概念なので(C++言語に関する内容に言及しない)C言語の教科書を参照した方が良いでしょう。

関連するQ&A

  • C++ クラスをメンバにもつクラスについて

    お世話になります。C++初心者でうまくコードが書けません(><) クラス1と2があり、クラス1のメンバにはクラス2があります。 メインでクラス1をインスタンス化してクラス2のfunc2を呼び出します。 func2ではクラス1のインスタンスから呼び出された場合にクラス1の m_int1を取得します。 Class Class1{ public:  int m_int1;  Class2 m_Class2; }; Class Class2{ public: void func2(); }; void Class2::func2(){  /*ここの記述方法が分かりません*/  /*C1から呼び出されたらC1のm_int1に100を入れる*/  /*以下間違え*/  class1 C2_1;/*別のclass1のオブジェクトなのでこれに入れてもダメっぽい*/  C2_1.m_int1 = 100; } void main(){  class1 C1;  C1.m_int1 = 10;  C1.m_class2.func(); } C1.m_class2.func()の中から呼び出したC1にアクセスする方法が 分かりません(TT)。実体がまだあるのだからアクセスする方法は あると思うのですが・・・ どなたかよろしくお願いします。

  • クラス内の関数内static変数について

    クラス内の「staticではないメンバ関数内で定義される」static変数の初期化タイミングはいつでしょうか? 自分としてはクラスのインスタンス生成時に初期化されるものだと思っていたのですが、どうもそうでは無さそうだという現象に出会ったもので。 例えば以下のようなサンプルプログラムがあるとします。 --------------------------------------- class TA { public: void func(int i); }; void TA::func(int i) { static int d=0; d += i; std::cout << d << std::endl; } int main() { for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); } } --------------------------------------- これを実行した時、自分としては 1 2 3 2 4 6 という結果を期待していた訳ですが、実際には 1 2 3 5 7 9 という結果になりました。 ということは、もしかしてメンバ変数ではなくともクラス内に現れるstatic変数はstaticなメンバ変数と同等ということなのでしょうか? 実際、上記ソースのforループ内にもう一つclass TAのインスタンスtbを追加してみると、 --------------------------------------- for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); TA tb; tb.func(i); tb.func(i); tb.func(i); } --------------------------------------- 1 2 3 4 5 6 8 10 12 14 16 18 となりました。 (まぁstaticではないメンバ変数に置き換えれば一応解決するのですが、個人的に何か凄く気持ち悪く感じて・・・)

  • クラスがメンバーとしてクラスを持つ時の宣言について

    自作クラスMainClassがMyClassというクラスをメンバー変数として持つ場合、宣言時に引数をいくつか持つコンストラクタを呼び出そうとすると構文エラーとなります。 class MyClass { public: MyClass(int, int); } class MainClass { private: MyClass myclass(10,10); } このような宣言はできないのでしょうか。 引数なしのコンストラクタは呼び出せているようです。

  • C++ 静的クラスの役割が分からない

    こんばんは。 C++で静的オブジェクトがなんなのか試しにプログラミングしているんですが どんな役割があるのか試してもよく分かりません。 static class HOGE { public: int *hoge; private: int value[2]; char moji[6]; public: HOGE() { cout << "HOGE\n"; } void MOJI() { strcpy(moji, "MOJI\n"); } void TEST() { cout << "moji = " << moji << endl; } static void staticMOJI() { } }sObj; sObjからは静的メンバ関数と静的メンバ変数は呼び出せるようです。他は呼び出せません。 そのようにするためにstatic宣言をするものなのでしょうか? このsObjからメンバ変数(*hoge)を呼び出すことは無理なんでしょうか?

  • C#でクラス継承について

    下記のようなコードは、可能なのでしょうか? // クラス定義 abstract class Base { int a; Public int A { get{ return a; } } } class Sub1 : Base { int b; public int B { set { b = value; } } }; class Sub2 : Base { // 中略 } static class Program { [STAThread] static void Main(string [] args) { Base aaa = new Sub1(); Base bbb = new Sub2(); func(aaa); // ここでCS1502, CS1503 func(bbb); // ここでCS1502, CS1503 } void func(Sub1 _aaa) { // 中略 } void func(Sub2 _bbb) { // 中略 } } コメントに書いたとおり、CS1502(引数が合わない)が出ます。 func((Sub1)aaa); の様にキャストしないと、動作させることは難しいでしょうか? ※ 実際のコードでは、func(aaa), func(bbb)の呼び出し部分をループでまわしたいと考えています。

  • フレンドクラスにできない

    mediatorクラスからCOuterクラスのメンバ変数にアクセスできるようにフレンドクラスにしたつもりなんですが、 うまくアクセスができずコンパイルエラーになってしまいます。 どこが悪いのか分からず困っています。 どなたか助けていただけませんか? mediator.h ----------------------------------------------------- template <class T> class mediator { public: mediator(T* p=NULL) : m_p(p) {} void SetOutClass(T*p) { m_p = pT;} T& GetOutClass() const { return *m_p;} private: T* m_p; }; #define outer GetOutClass() ----------------------------------------------------- COuter.h ----------------------------------------------------- class COuter { private: int m_a; public: void func() { class CInner : public mediator<COuter> { public: CInner(COuter *p) : mediator<COuter>(p) {} void func() { // フレンドクラスなのにアクセスできない!? outer.m_a = 1; } }; CInner inner(this); inner.func(); } friend class mediator<COuter>; }; -----------------------------------------------------

  • 試作クラス使用C++プログラムが動かない原因

    試しに作成した以下のプログラムにビルドエラーが発生し,困っているので質問しました. コンパイラは,「BBB *b」などクラスポインタ変数の部分がエラーと指摘しているのですが(他にも数か所ありますが…),間違っている理由が分からず困ってます. ご回答,よろしくお願い致します. ----------------------------------- #include <iostream> using namespace std; class AAA { public: // コンストラクタ AAA(){ b = new BBB( this ); } // デストラクタ ~AAA(){ delete b; } // メンバ変数 BBB *b; int i; // メンバ関数 void displayB(){ b->displayA(); } }; class BBB { public: // コンストラクタ BBB( AAA *a ){ this->a = a; } // デストラクタ ~BBB(){} // メンバ変数 AAA *a; int j; // メンバ関数 void displayA(){ printf( "%d\n", a->i ); } }; int main() { // 変数の定義 AAA a; // 変数の初期化 a.i = 2; a.b->j = 5; // 出力 printf( "%d\n", a.i ); a.b->displayA(); return 0; } -----------------------------------

  • 親クラスのポインタで派生クラスの関数呼び出し

    下記のようなクラス構成があるとします。 説明のため簡略化しています。 [Test.h] class CParent { protected: int nParent; public: CParent(){nParent = 10;} ~CParent(){}; virtual int func1(){ // (*1) return nParent; } }; class CSub : public CParent { int m_nSub1; // 派生クラスにしかないメンバ変数 int m_nSub2; // 派生クラスにしかないメンバ変数 public: CSub(){m_nSub = 20;} ~CSub(){}; int func1(){ // (*3) return nParent*2; // 20 } // 派生クラスにしかないメンバ関数 int func2() // (*4) { m_nParent; // 10 return m_nSub1; // 不定値 } int SetData(int n) // (*5) { m_nSub2 = n; return m_nSub2; } }; [Test.cpp] void main() { CParent parent; // 親クラスのオブジェクト CParent* pParent = &parent; // 親クラスのオブジェクトを指すポインタ int nRet = 0; nRet = pParent->func1(); // (*1) // サブクラスのポインタ型にキャストする CSub* pSub = (CSub*)pParent; // (*2) nRet = pSub->func1(); // (*3) nRet = pSub->func2(); // (*4) nRet = pSub->SetData(60); // (*5) } (*3)ではpSubの指すオブジェクトが親クラス(CParent)のため、ポリモーフィズムのメカニズムに従ってCParent::func1()が呼ばれ10が返ってきます。ここまでは想定通りです。 次の(*4)ですが、これはCSub::func2()が呼ばれています。なぜこの呼び出しで子クラスの関数を呼ぶことが出来るのでしょうか? 実際その動作をさせたいのですが、なぜそうなるのかが分かりません。想定ではpSubが指す先は親クラスのため、子クラスにしかないメンバ関数func2()は呼べないはずです。 このコードでは、CSubのコンストラクタは通りませんので(そもそもCSub型のインスタンスは実体化していない)、(*4)の呼び出しでは不定値が返ります。また、(*5)は期待通り動作し、戻り値60が返っています。 これは危険な事をしているのでしょうか? 期待通りではあるのですが、なぜこのような動作になるのか理解できません。 上記のようなことをしたい場合、どのように記述するべきでしょうか?

  • C++でfriendクラスにしているのにprivateメンバにアクセスできない

    C++でメンバ変数をprivateにして、特定のクラスにだけ公開するようにクラスをfriend指定したのですがprivateメンバにアクセスできませんとエラーが吐かれてしまいます。 先行宣言したりもしてみたのですがどうしても使用できません。 何か心当たりのあるかた教えてください。 class A { friend class B; private: int a; }; class B { public: void test( A *a ) { a->a = 0; } }; コードは違いますがこんな感じのことをしたいのです。 /* コンソールで小さなプログラムでテストしてみると動くのにいざ実際のソースに組み込むと動かないという奇妙な状態です。よろしくお願いします。 */

  • 【C++】クラス内のメンバ関数の占める領域

    C++のことです(恐らく、他言語にも共通していると思いますが)。 例えば、 class a { void func(); }; という風なクラスがあったとして、これを a kurasu[100]; と言う風にインスタンスを生成した場合、メンバ関数funcも100個分作られるのでしょうか。 “関数が作られる”って言い方は適切でないかもしれませんが……。。。 100個分の関数用にメモリが割り当てられるのか、といったニュアンスです。 よろしくお願いします。

専門家に質問してみよう