C++Primer学習ノート_25_クラスとデータ抽象(7)--staticメンバー変数、staticメンバー関数、クラス/オブジェクトのサイズ


一、static
各staticデータメンバーはクラスに関連付けられたオブジェクトであり、クラスのオブジェクトには関連付けられていません.非staticデータメンバーはクラスタイプの各オブジェクトに存在し、staticデータメンバーはクラスの任意のオブジェクトから独立して存在します.
staticメンバー関数にはthisパラメータはありません.所属するクラスのstaticメンバーに直接アクセスできますが、staticメンバーを直接使用することはできません.
1、staticメンバー変数
(1)staticメンバーの概念
特定のタイプのオブジェクト全体に対して、グローバル変数にアクセスする必要がある場合があります.たとえば、あるタイプのオブジェクトが作成された数を統計します.
【2】グローバル変数を使用するとデータのカプセル化が破壊され、一般的なユーザコードはこのグローバル変数を修正することができ、この場合、クラスの静的メンバーでこの問題を解決することができる.
非staticデータメンバーは、クラスタイプの各オブジェクトに存在し、staticデータメンバーは、クラスに関連付けられたオブジェクトであり、クラスオブジェクトに関連付けられていないクラスの任意のオブジェクトから独立して存在する(共有される).
(2)staticメンバーの利点
staticメンバーの名前はクラスの役割ドメインにあるので、他のクラスメンバーまたはグローバルオブジェクトの名前との競合を回避することができる.
【2】パッケージを実装することができ、staticメンバーはプライベートであってもよく、グローバルオブジェクトは使用できない
読解プログラムは、staticメンバーがクラスに関連付けられていることを容易に見ることができ、この可視性はプログラマーの意図を明確に反映することができる.
【4】役割ドメインオペレータによってクラスからstaticメンバーを直接呼び出すか、またはオブジェクト、参照、またはクラスタイプオブジェクトへのポインタによって間接的に呼び出すことができる.staticメンバーは通常の公有/プライベートアクセス規則に従う
【5】例
//CountedObject.h
#ifndef _COUNTED_OBJECT_H_
#define _COUNTED_OBJECT_H_
class CountedObject
{
public:
    CountedObject();
    ~CountedObject();
public:
    static int GetCount();
private:
    static int count_;	 //           
};
#endif // _COUNTED_OBJECT_H_
//CountedObject.cpp
#include "CountedObject.h"
int CountedObject::count_ = 0;	 //           
CountedObject::CountedObject()
{
 ++count_;
}
CountedObject::~CountedObject()
{
 --count_;
}
int CountedObject::GetCount()
{
 return count_;
}
//01.cpp
#include "CountedObject.h"
#include <iostream>
using namespace std;
int main(void)
{
     //cout<<CountedObject::count_<<endl;  //Error
     cout<<CountedObject::GetCount()<<endl;
     CountedObject co1;
     cout << co1.GetCount() << endl; //        
     cout<<CountedObject::GetCount()<<endl;  //               
     CountedObject* co2 = new CountedObject;
     cout << co2->GetCount() << endl;//                 
     cout<<CountedObject::GetCount()<<endl;
     delete co2;
     cout<<CountedObject::GetCount()<<endl;
}

実行結果:
0 1 1 1 2 1説明:上記のプログラムは静的メンバー変数と静的メンバー関数を定義し、クラス名::staticメンバー関数にアクセスするか、非/静的メンバー関数にアクセスできます.
(3)staticメンバーの定義
staticメンバーは、クラス定義の体外で初期化および定義する必要があります(クラス内では宣言のみ)
//02.cpp
#include <iostream>
using namespace std;
class Test
{
public:
     Test()  { }
     ~Test() { }
     static int x_;	 //           
};
int Test::x_ = 100; //           
int main(void)
{
     cout << Test::x_ << endl;
}

実行結果:
100
(4)特殊な整数static constメンバー
【1】完全static constメンバーはクラス定義体で初期化することができ、そのメンバーはクラス体外で定義しなくてもよい
【2】整数型の場合、3つのケースがあります.1つ目は、クラス内で宣言することができますが、クラス定義の体外で定義初期化を行う必要があります.constは初期化する必要があるためです.2つ目は、ここで定義初期化を直接行うと、クラス定義の体外で値を付与することができず、constは値を再付与することができません.3つ目は、コンストラクション関数の初期化リストでの初期化は絶対に許されません.注意:非整数の場合、ここで初期化することはできません.整数にはchar、short、long、int(float、doubleはできません)が含まれます.
【3】例
//02.cpp
#include <iostream>
using namespace std;
class Test
{
public:
     Test()  { }
     ~Test() { }
     static const int x_ = 100;	 //           
     //static const double x_ = 100;	 // Error
};

int main(void)
{
     cout << Test::x_ << endl;
}

実行結果:
100
2、staticメンバー関数
(1)staticメンバー関数には隠されたthisポインタがありません(静的メンバー関数は非静的メンバー関数と非静的メンバー関数に直接アクセスできません)
(2)非静的メンバー関数静的メンバー関数と静的メンバー関数(3)静的メンバー関数は非静的メンバーに直接アクセスできません(実際には直接アクセスできませんが、間接的にアクセスできます.例えば、クラスポインタやクラス参照など)
(4)staticメンバーはオブジェクトのコンポーネントではないため、staticメンバー関数をconstとして宣言することはできません.結局、メンバー関数をconstとして宣言することは、その関数が属するオブジェクトを変更しないことを約束します.
(5)最後にstaticメンバー関数も虚関数として宣言できない(後述).
(6)例
//03.cpp
#include <iostream>
using namespace std;
class Test
{
public:
    Test(int y) : y_(y) { }
    ~Test() { }
    void TestFun()
    {
        cout << "x=" << x_ << endl; //OK,                    
        TestStaticFun();
    }
    static void TestStaticFun()
    {
        cout << "TestStaticFun ..." << endl;
        //TestFun();        Error,                 
        //cout<<"y="<<y_<<endl;     Error,               
    }
    static int x_;      //               
    int y_;    //        
};
int Test::x_ = 100;     //           
int main(void)
{
    Test t(10);
    cout << Test::x_ << endl;
    t.TestFun();
    cout << t.x_ << endl;  //    ,      ,   Test::x_
    return 0;
}

実行結果:
100
x=100
TestStaticFun ...
100
二、クラス/オブジェクトサイズ計算
(1)クラスサイズ計算は前述の構造体整列の原則に従う
(2)クラスのサイズはデータメンバーに関係する(空のクラスサイズは1バイト)
(3)クラスのサイズはメンバー関数に関係なく
(4)クラスのサイズは静的データメンバーに関係なく(5)虚関数がクラスのサイズに及ぼす影響は,後で考慮する.
(6)ダミー継承がクラスの大きさに与える影響は,後で考える.
【例】
#include <iostream>
using namespace std;

class Test
{
public:
    Test(int y) : y_(y) { }
    ~Test() { }

    void TestFun()
    {
        cout << "x=" << x_ << endl; //OK,               
        TestStaticFun();
    }

    static void TestStaticFun()
    {
        cout << "TestStaticFun ..." << endl;
        //TestFun();        Error,                  
        //cout<<"y="<<y_<<endl;     Error,                
    }
    static int x_;      //                
    int y_;    //        
};

int Test::x_ = 100;     //           

int main(void)
{
    cout << sizeof(Test) << endl;
    return 0;
}

実行結果:
4
説明:上記はクラスのデータメンバーのみに関係し、intタイプが定義されているため、クラスサイズは4バイトです.
参照先:
C++primer第4版