marunomaruno-memo

marunomaruno-memo

[C++] クラス定数の補足

2011年11月18日 | Android
                                                                更新 2012-10-08
                                                                新規 2011-11-18
クラス定数の補足
================================================================================

クラス定数は、次の形で定義できる。
    static const データ型 定数名 = 値;

ただし、データ型は、int や double など、基本データ型である必要がある。
char* のように、ポインター型や、char [] のような配列、std::string のようなオブジ
ェクトでは
invalid in-class initialization of static data member of non-integral type 
`const char*'
のようなコンパイル・エラーとなる。
つまり、(キャストして)整数や実数となるような型でないとだめのようだ。

後述するが、上記のように書けない場合は、クラス宣言の中で
    static const データ型 定数名;
としておいて、実体を定義するときに
    static const データ型 クラス名::定数名 = 値;
とする必要がある。(2012-10-08追記)

□ Sample.cpp
---
#include <iostream>
#include <string>
using namespace std;

class A {
private:
    int data;
    double data2;
    bool data3;

public:
    static const int DATA = 1234;    // (1)
    static const double DATA2 = 3.14;    // (1)
    static const bool DATA3 = true;    // (1)
    //    static const char* MESSAGE = "Hello World!"; // コンパイルエラー // (2)
    A(int data = DATA, double data2 = DATA2, bool data3 = DATA3);    // (3)
    void print();
};

A::A(int data, double data2, bool data3) : data(data), data2(data2), data3(data3) {
}

void A::print() {
    cout << data << ", " << data2 << ", " << data3 << endl;
}

int main() {
    cout << A::DATA << endl; // prints Hello World!
    cout << A::DATA2 << endl; // prints Hello World!
    cout << A::DATA3 << endl; // prints Hello World!
    //    cout << A::MESSAGE << endl; // prints Hello World!
    A a;
    a.print();

    return 0;
}
---

□ 実行結果
---
1234
3.14
1
1234, 3.14, 1
---


(1) クラス定数の定義

    static const int DATA = 1234;    // (1)
    static const double DATA2 = 3.14;    // (1)
    static const bool DATA3 = true;    // (1)

(2) ポインターをクラス定数で定義

    //    static const char* MESSAGE = "Hello World!"; // コンパイルエラー // (2)

これは、
invalid in-class initialization of static data member of non-integral type 
`const char*'
でコンパイル・エラーになる。


(3) クラス定数をデフォルト引数に指定

    A(int data = DATA, double data2 = DATA2, bool data3 = DATA3);    // (3)

とくに問題はない。


(以下、2012-10-08 追記)

■ 自分自身のインスタンスを定数で持つクラス

自分自身のインスタンスを定数で持つクラスのサンプル。

メンバー変数は、たんに int 型の値を持っているだけ。
コンストラクターをすべて private にすれば、他から直接インスタンスを生成できない
ようにすることもできる。


□ Item.h
---
#ifndef ITEM_H_
#define ITEM_H_

#include <iostream>

class Item {
public:
    static const Item* ITEM1;    // (1)
    static const Item* ITEM2;    // (1)

    static const Item* ITEM_LIST[];    // (2)
    static const int ITEM_LIST_SIZE;    // (3)

private:
    int value;

public:
    Item();
    Item(int value);
    virtual ~Item();

    int getValue() const;
};

#endif /* ITEM_H_ */
---

(1) 自分自身のオブジェクトの定数の宣言

    static const Item* ITEM1;    // (1)
    static const Item* ITEM2;    // (1)

(2)(3) オブジェクト定数配列の宣言とその要素数の宣言

オブジェクト定数を配列で持っていることで、使い勝手が向上するかもしれない。
そのときの要素数も持たせておく。

    static const Item* ITEM_LIST[];    // (2)
    static const int ITEM_LIST_SIZE;    // (3)

ここで、ITEM_LIST_SIZE は int 型だから、
    static const int ITEM_LIST_SIZE = sizeof(Item::ITEM_LIST)
                / sizeof(Item::ITEM_LIST[0]);
とすると、つぎのメッセージでコンパイルエラーとなる。
    invalid application of `sizeof' to incomplete type `const Item*[]' 
この時点では、ITEM_LIST の要素が確定していないため。


□ Item.cpp
---
#include <iostream>
#include <cassert>
#include "Item.h"

const Item* Item::ITEM1 = new Item(10);    // (1)
const Item* Item::ITEM2 = new Item(20);    // (1)

const Item* Item::ITEM_LIST[] = { ITEM1, ITEM2 };    // (2)
const int Item::ITEM_LIST_SIZE = sizeof(Item::ITEM_LIST)
        / sizeof(Item::ITEM_LIST[0]);    // (3)

Item::Item() {
    assert(true);
}

Item::Item(int value) :
        value(value) {
    assert(true);
}

Item::~Item() {
    assert(true);
}

int Item::getValue() const {
    return value;
}
---

(1) 自分自身のオブジェクトの定数の定義

const Item* Item::ITEM1 = new Item(10);    // (1)
const Item* Item::ITEM2 = new Item(20);    // (1)


(2) オブジェクト定数配列の定義

const Item* Item::ITEM_LIST[] = { ITEM1, ITEM2 };    // (2)


(3) オブジェクト定数配列の要素数の定義

const int Item::ITEM_LIST_SIZE = sizeof(Item::ITEM_LIST)
        / sizeof(Item::ITEM_LIST[0]);    // (3)


□ ItemTest.cpp
---
#include <iostream>
using namespace std;

#include "Item.h"

int main() {
    cout << Item::ITEM1->getValue() << endl;
    cout << Item::ITEM2->getValue() << endl;

    for (int i = 0; i < Item::ITEM_LIST_SIZE; ++i) {
        cout << Item::ITEM_LIST[i]->getValue() << endl;
    }

    Item item;
    cout << item.getValue() << endl;

    Item item2(30);
    cout << item2.getValue() << endl;

    return 0;
}
---


□ 実行結果
---
10
20
10
20
0
30
---

                                                                            以上