2.2.5. クラスとしてArrayを実装した例

この例ではArrayをクラスとして定義し、今まで関数として書いてきたものを メンバ関数にしています。

 1// s003: dynamically allocated array held on a struct
 2// along with the data count.
 3//
 4#include <iostream>
 5#include <cassert>
 6
 7const int N_SIZE = 10;
 8
 9class Array
10{
11private:
12    double *parray_;
13    int n_size_;
14
15public:
16    ~Array();
17
18    Array(int n_size);
19
20    void set_dummy_data();
21
22    void copy_data(const Array &other);
23
24    void print_data(std::ostream &os) const;
25
26    // accessors
27    double &at(int i) { return parray_[i]; }
28    double const &at(int i) const { return parray_[i]; }
29
30    int size() const { return n_size_; }
31};

Array クラスの定義の中ではメソッドを宣言したり定義したりしています。

メソッドの形だけ書いて処理の中身を書かないのが宣言で、処理の中身まで書いてあるの が定義です。

33Array::Array(int n_size)
34{
35    parray_ = new double[n_size];
36    n_size_ = n_size;
37}

クラス名と同じ名前のメソッドはコンストラクタ。

コンストラクタの中にnewが書いてあり、もしもメモリ不足が起きたら throw std::bad_alloc されるので、このコンストラクタを呼ぶと std::bad_alloc 例外 が「上がってくる」可能性があります。

39Array::~Array()
40{
41    delete [] parray_;
42}

名前が「~」+クラス名のデストラクタではメモリを解放します。

44void Array::set_dummy_data()
45{
46    for (int i = 0; i < size(); i++)
47    {
48        at(i) = static_cast<double>(i) / static_cast<double>(size());
49    }
50}
51
52void Array::copy_data(const Array &src)
53{
54    assert(size() == src.size());
55    for (int i = 0; i < size(); i++)
56    {
57        at(i) = src.at(i);
58        // 左辺の at は double &at(int i)
59        // 右辺の at は double const &at(int i) const
60        // 違いを生み出しているのは変数thisに const がついているか。
61    }
62}
63
64void Array::print_data(std::ostream &os) const
65{
66    os << "[";
67    for (int i = 0; i < size(); i++)
68    {
69        os << at(i);
70        if (i < size() - 1)
71        {
72            os << ", ";
73        }
74    }
75    os << "]\n";
76}

前の例での関数は、ここではメソッドになっています。

69行目の at(i) は、同一オブジェクトの at メソッドの呼び出しです。

 78int main(int argc, const char *argv[])
 79{
 80    std::cout << "s005\n";
 81
 82    // allocate array dynamically on the heap area.
 83    Array array1(N_SIZE);
 84    Array array2(N_SIZE);
 85
 86    // 静的領域のメモリの初期値は 0
 87    // ただし自分で初期値を入れることが推奨される。
 88    std::cout << "Before initialization\n";
 89    array1.print_data(std::cout);
 90
 91    // 配列の名前のデータ型は配列要素のアドレス。
 92    // 受ける側のdoubleのポインタに代入できる。
 93    array1.set_dummy_data();
 94    std::cout << "After initialization\n";
 95    array1.print_data(std::cout);
 96
 97    array2.copy_data(array1);
 98    std::cout << "After array copy\n";
 99    array2.print_data(std::cout);
100
101    return EXIT_SUCCESS; // exit status code 0
102}

83,84行目で Array 型の変数を定義している行で、コンストラクタが呼ばれます。 関数から抜ける際にデストラクタが呼ばれます。

全体のソースを以下に示します:

  1// s003: dynamically allocated array held on a struct
  2// along with the data count.
  3//
  4#include <iostream>
  5#include <cassert>
  6
  7const int N_SIZE = 10;
  8
  9class Array
 10{
 11private:
 12    double *parray_;
 13    int n_size_;
 14
 15public:
 16    ~Array();
 17
 18    Array(int n_size);
 19
 20    void set_dummy_data();
 21
 22    void copy_data(const Array &other);
 23
 24    void print_data(std::ostream &os) const;
 25
 26    // accessors
 27    double &at(int i) { return parray_[i]; }
 28    double const &at(int i) const { return parray_[i]; }
 29
 30    int size() const { return n_size_; }
 31};
 32
 33Array::Array(int n_size)
 34{
 35    parray_ = new double[n_size];
 36    n_size_ = n_size;
 37}
 38
 39Array::~Array()
 40{
 41    delete [] parray_;
 42}
 43
 44void Array::set_dummy_data()
 45{
 46    for (int i = 0; i < size(); i++)
 47    {
 48        at(i) = static_cast<double>(i) / static_cast<double>(size());
 49    }
 50}
 51
 52void Array::copy_data(const Array &src)
 53{
 54    assert(size() == src.size());
 55    for (int i = 0; i < size(); i++)
 56    {
 57        at(i) = src.at(i);
 58        // 左辺の at は double &at(int i)
 59        // 右辺の at は double const &at(int i) const
 60        // 違いを生み出しているのは変数thisに const がついているか。
 61    }
 62}
 63
 64void Array::print_data(std::ostream &os) const
 65{
 66    os << "[";
 67    for (int i = 0; i < size(); i++)
 68    {
 69        os << at(i);
 70        if (i < size() - 1)
 71        {
 72            os << ", ";
 73        }
 74    }
 75    os << "]\n";
 76}
 77
 78int main(int argc, const char *argv[])
 79{
 80    std::cout << "s005\n";
 81
 82    // allocate array dynamically on the heap area.
 83    Array array1(N_SIZE);
 84    Array array2(N_SIZE);
 85
 86    // 静的領域のメモリの初期値は 0
 87    // ただし自分で初期値を入れることが推奨される。
 88    std::cout << "Before initialization\n";
 89    array1.print_data(std::cout);
 90
 91    // 配列の名前のデータ型は配列要素のアドレス。
 92    // 受ける側のdoubleのポインタに代入できる。
 93    array1.set_dummy_data();
 94    std::cout << "After initialization\n";
 95    array1.print_data(std::cout);
 96
 97    array2.copy_data(array1);
 98    std::cout << "After array copy\n";
 99    array2.print_data(std::cout);
100
101    return EXIT_SUCCESS; // exit status code 0
102}

Download the source code

実行例を示します

% ./s005
s005
Before initialization
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
After initialization
[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
After array copy
[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]