そろそろC++やります
そろそろC++をやります。そろそろC++をやりたいからです。
何回やるかはわかりません。基礎を理解するまではやろうと思います。
という感じでやっています。
※ 初心者がメモレベルで記録するので、技術記事としてはお力になれないかもしれません。
内容
配列の初期化
基本型の配列の初期化はこちらで触れています。 自作クラス(参照型の配列)について、触れていきます。
こちらのPosition
を使います。
class Position { public: Position(int x, int y) { } };
int
型の配列の場合はint ar[2];
として宣言することが出来ましたが、コンストラクタがあるクラスの場合はできません。
int main() { // error: no matching constructor for initialization of 'Position[3]' Position positions[3]; return 0; }
配列分の要素のコンストラクタが必要です。
Position positions[3]{ Position(0, 0), Position(0, 0), Position(0, 0)};
ただ、コンストラクタを書かないで、デフォルトコンストラクタとする場合は、コンストラクタを書かずに配列の宣言ができます。
class Position { public: // default constructor // Position(int x, int y) // { // } }; int main() { Position positions[3]; return 0; }
クラスの配列の場合は、波括弧({ }
)か、for
文回すかで初期化は必ずした方が良さそうです。
配列の要素へのアクセス
今まで[ ]
を用いてアクセスしていましたが、改めて。配列添字演算子([ ]
)を使用すると配列の個々の要素にアクセスできます。 Pythonのように、[-1]
で最後の要素にアクセスする機能はありません。
int ar[3]{3, 6, 9}; for (int i = 0; i < 3; i++) { cout << ar[i] << endl; }
添字なしで一次元配列の名前を指定すると、先頭の要素のポインターとして評価されます。
if (ar == &ar[0]) { cout << "Same Address" << endl; } // Output: // Same Address
多次元配列でポインターを使用すると特定の列のみ抜き出すことができます。
int ar[3][2]{{3, 6}, {1, 6}, {2, 35}}; int *ar1Ptr = ar[1]; for (int i = 0; i < 2; i++) { cout << ar1Ptr[i] << endl; } // Output: // 1 // 6
ドキュメントを正確に読むと、先頭の要素のポインターとして『評価されます』。評価されます。と書いてあります。
配列の変数を右辺に置き、評価された後のポインターを、ポインターの変数に代入することは可能ですが、ポインターを代入することはできません。
int *ar1Ptr = ar[1]; // error: array type 'int[2]' is not assignable ar[1] = ar1Ptr;
先ほど、Pythonのように-1
で最後の要素へのアクセスはないと大ましたが、入れつの中の要素をポインターとして持つことで、負の数へのアクセスを実現できます。
int ar[5]{19, 17, 15, 13, 11}; int *arPtr = &ar[2]; cout << arPtr[-2] << endl; cout << arPtr[-1] << endl; cout << arPtr[0] << endl; // Output: // 19 // 17 // 15
演算子のオーバーロード
他の演算子のように、添字演算子 ([]) は、ユーザーが再定義できます。 基本は、次のメソッドを使用して配列名と添字を組み合わせます。
*((array_name) + (subscript))
subscript
は添字という意味で、こちらに詳細が載っています。これらは同じ表現となります。
cout << *(ar + i) << endl; cout << ar[i] << endl; cout << i[ar] << endl;
こちらを参考にすると、
class DataStoreArray { public: DataStoreArray(std::size_t size) : mValueArray(new int[size]) { } ~DataStoreArray() { delete[] mValueArray; } inline int operator[](std::size_t index) const { cout << "in" << endl; return mValueArray[index]; } inline int &operator[](std::size_t index) { cout << "out" << endl; return mValueArray[index]; } private: int *mValueArray; }; int main() { DataStoreArray storage = DataStoreArray(10); storage[4] = 14; cout << storage[4] << endl; return 0; } // Output: // 14
ただ、こちらは演算子のオーバーロードの時に詳しく触れたいと思います。
参考リスト
- 配列 (C++) | Microsoft Learn
- 添字演算子 [] | Microsoft Learn
- 演算子オーバーロード | Programming Place Plus C++編【言語解説】 第19章
感想
本日で配列は終わりになります。今までに4回
1. 導入と定数式
2. スタックとヒープ
3. 初期化と関数渡し
4. 多次元配列
今回で5回でした。途中途中で少し気になることの調査で脱線したものの、かなり理解できたと思います。
ただ初回に触れたように、std::array
やstd::vector
がお勧めされており、こちらにも触れていきたいなと思います。
次回はポインターについて、触れていきたいと思います。