static (静的) 解答ページ | Programming Place Plus C++編【言語解説】 第18章

トップページC++編

C++編で扱っている C++ は 2003年に登場した C++03 という、とても古いバージョンのものです。C++ はその後、C++11 -> C++14 -> C++17 -> C++20 -> C++23 と更新されています。
なかでも C++11 での更新は非常に大きなものであり、これから C++ の学習を始めるのなら、C++11 よりも古いバージョンを対象にするべきではありません。特に事情がないなら、新しい C++ を学んでください。 当サイトでは、C++14 をベースにした新C++編を作成中です。

問題①

問題① staticメンバ変数が、オブジェクトの大きさに影響を与えないことを確認してください。


sizeof演算子を使って調べれば良いでしょう。

#include <iostream>

class Test {
private:
    int mValue;
//    static int mStaticValue;
};

//int Test::mStaticValue;


int main()
{
    std::cout << sizeof(Test) << std::endl;
}

staticメンバ変数^の箇所のコメントを外しても、外さなくても、出力結果は 4 になりました。したがって、staticメンバ変数はオブジェクトの大きさに影響を与えません。

問題②

問題② 次のプログラムの実行結果を答えてください。

// MyClass.h
#ifndef MYCLASS_H_INCLUDED
#define MYCLASS_H_INCLUDED

class MyClass {
public:
    MyClass(int value);
    ~MyClass();

    inline int GetValue() const
    {
        return mValue;
    }

    static inline int GetObjectCount()
    {
        return msObjectCount;
    }

private:
    int mValue;
    static int msObjectCount;
};

#endif
// MyClass.cpp

#include "MyClass.h"

int MyClass::msObjectCount = 0;

MyClass::MyClass(int value) :
    mValue(value)
{
    ++msObjectCount;
}

MyClass::~MyClass()
{
    --msObjectCount;
}
// main.cpp

#include "MyClass.h"

MyClass* func(int value)
{
    static MyClass c(value);

    MyClass* p = new MyClass(value);

    std::cout << MyClass::GetObjectCount() << " "
              << c.GetValue() << " "
              << p->GetValue() << " " << std::endl;

    return p;
}

int main()
{
    static const int LOOP_COUNT = 3;

    MyClass* c[LOOP_COUNT];

    for (int i = 0; i < LOOP_COUNT; ++i) {
        c[i] = func(i);
    }

    for (int i = 0; i < LOOP_COUNT; ++i) {
        delete c[i];
    }
}

出力している値は、「オブジェクトの総数」「静的ローカル変数 c の mValue の値」「ローカル変数 p の mValue の値」です。

まず、1回目の func関数の呼び出しで、静的ローカル変数 c のオブジェクトが作られます。この時点で、オブジェクトの総数が 1 になり、mValue の値は 0 になります。続けて、new によって、動的にオブジェクトが生成され、オブジェクトの総数は 2 に増えます。mValue の値は 0 です。したがって、1回目の出力内容は「2」「0」「0」となります。

2回目の func関数の呼び出しでは、静的ローカル変数 c はすでに作られているので、c に対しては何も起こりません。動的なオブジェクト生成は行われ、1回目のときとは異なる新しいオブジェクトが作られるので、オブジェクトの総数が増えます。func関数の実引数は 1 なので、mValue の値は 1 になります。したがって、2回目の出力内容は「3」「0」「1」となります。

3回目の func関数の呼び出しも、基本的に同じ流れになります。したがって、3回目の出力内容は「4」「0」「2」となります。

以上、出力結果は次のようになります。

実行結果:

2 0 0
3 0 1
4 0 2

問題③

問題③ あるクラスがインスタンス化されたときに、各オブジェクトに重複がない個別の ID (整数値) を割り当てたいとします。staticメンバ変数を利用して、このような割り当てを自動化できるようにクラスを設計してください。


重複が無ければ良いだけなので、0 から初めて、連番を振っていくという実装で良いでしょう。次に割り当てる ID を覚えておく staticメンバ変数を用意すれば、実現できます。

// MyClass.h
#ifndef MYCLASS_H_INCLUDED
#define MYCLASS_H_INCLUDED

class MyClass {
public:
    MyClass();

    inline int GetId() const
    {
        return mId;
    }

private:
    int mId;
    static int msNextId;
};

#endif
// MyClass.cpp

#include "MyClass.h"

int MyClass::msNextId = 0;

MyClass::MyClass()
{
    mId = msNextId;
    ++msNextId;
}
// main.cpp

#include "MyClass.h"

int main()
{
    for (int i = 0; i < 5; ++i) {
        MyClass c;
        std::cout << c.GetId() << std::endl;
    }
}

実行結果:

0
1
2
3
4

ちなみに、staticメンバ変数ではなく、staticグローバル変数を使うのでも良いです。

// MyClass.h
#ifndef MYCLASS_H_INCLUDED
#define MYCLASS_H_INCLUDED

class MyClass {
public:
    MyClass();

    inline int GetId() const
    {
        return mId;
    }

private:
    int mId;
};

#endif
// MyClass.cpp

#include "MyClass.h"

namespace {
    int sNextId = 0;
}


MyClass::MyClass()
{
    mId = sNextId;
    ++sNextId;
}
// main.cpp

#include "MyClass.h"

int main()
{
    for (int i = 0; i < 5; ++i) {
        MyClass c;
        std::cout << c.GetId() << std::endl;
    }
}


参考リンク


更新履歴

’2018/9/10 第15章と内容を入れ替えた(以下の履歴は、旧第15章のもの)。
さらに全体的に見直し修正。

’2018/7/23 章のタイトルを変更(「static の使い方」–>「static (静的)」)

’2018/7/13 サイト全体で表記を統一(「静的メンバ」–>「staticメンバ」)

’2018/2/22 「サイズ」という表記について表現を統一。 型のサイズ(バイト数)を表しているところは「大きさ」、要素数を表しているところは「要素数」。

’2014/5/24 新規作成。



第18章のメインページへ

C++編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る