続いては添字演算子のオーバーロードについて説明します。
添字演算子とは「[ ]」です。
配列の添え字として使いますが、これをオーバーロードするとクラスが配列のように扱えます。
C#ではインデクサという名前になっています。
どのような使い方になるか、まずはベースとなるクラスを作ってみます。
<sample program cpp068-01>
#include <iostream> #include <vector> #include <cstdlib> #include <ctime> class Sample { public: Sample(); void Show() const; private: std::vector<int> m_vecInt; }; int main() { Sample sample; sample.Show(); return 0; } Sample::Sample() { srand((unsigned int)time(NULL)); int count = rand() % 6 + 5; for (int i = 0; i < count; i++) { m_vecInt.push_back((i + 1) * 10); } } void Sample::Show() const { for (unsigned int i = 0; i < m_vecInt.size(); i++) { std::cout << m_vecInt[i] << " "; } std::cout << std::endl; } |
<実行結果>
10 20 30 40 50 60 70 80 続行するには何かキーを押してください・・・
クラスのメンバとして「ベクタ」を用意しました。
乱数を使って、コンストラクタ関数で5から10個のデータをpushしています。
Show関数で「ベクタ」の中身を全て表示しました。
※小さいプログラムなので、直接値を書いているのは見逃してください・・・
当然、クラスの外からは「ベクタ」にアクセスする事は出来ませんので、「ベクタ」の要素を取り出そうと思うと↓のような関数を追加する必要があります。
<sample program cpp068-02>
#include <iostream> #include <vector> #include <cstdlib> #include <ctime> class Sample { public: Sample(); void Show() const; int GetElement(const unsigned int index) const; private: std::vector<int> m_vecInt; }; int main() { Sample sample; sample.Show(); std::cout << sample.GetElement(0) << std::endl; return 0; } Sample::Sample() { srand((unsigned int)time(NULL)); int count = rand() % 6 + 5; for (int i = 0; i < count; i++) { m_vecInt.push_back((i + 1) * 10); } } void Sample::Show() const { for (unsigned int i = 0; i < m_vecInt.size(); i++) { std::cout << m_vecInt[i] << " "; } std::cout << std::endl; } int Sample::GetElement(const unsigned int index) const { return m_vecInt[index]; } |
<実行結果>
10 20 30 40 50 60 70 80 90 10 続行するには何かキーを押してください・・・
GetElement関数を作る事で「ベクタ」の添え字(インデックス)を指定し、中身を取得する事が出来ます。
しかし、添字演算子をオーバーロードする事で、もっと直感的にアクセス出来るようになります。
まずは「読み取り専用」パターンから作ってみましょう。
上のプログラムからGetElement関数を削除し、添字演算子のオーバーロードを追加します。
<sample program cpp068-03>
#include <iostream> #include <vector> #include <cstdlib> #include <ctime> class Sample { public: Sample(); void Show() const; int operator[](const unsigned int index) const; private: std::vector<int> m_vecInt; }; int main() { Sample sample; sample.Show(); std::cout << sample[0] << std::endl; return 0; } Sample::Sample() { srand((unsigned int)time(NULL)); int count = rand() % 6 + 5; for (int i = 0; i < count; i++) { m_vecInt.push_back((i + 1) * 10); } } void Sample::Show() const { for (unsigned int i = 0; i < m_vecInt.size(); i++) { std::cout << m_vecInt[i] << " "; } std::cout << std::endl; } int Sample::operator[](const unsigned int index) const { return m_vecInt[index]; } |
<実行結果>
10 20 30 40 50 60 70 80 90 100 10 続行するには何かキーを押してください・・・
まずはプロトタイプ宣言を見てみましょう。
int operator[](const unsigned int index) const; |
引数として、添え字(インデックス)を渡しています。
「読み取り専用」ですから、中身の書き換えをさせないために後ろに「const」を付つけています。
戻り値も「ベクタ」の該当要素のコピーを返しているだけですので、外から書き換えられることもありません。
注目してほしいのはmain関数です。
std::cout << sample[0] << std::endl; |
あたかもクラスが配列のように扱えています。
※添え字の範囲チェックはしていませんので、オーバーロード本体で範囲チェックを入れる事も重要な事です。
今回は書きませんので、皆さんでassertなどを使って作ってみてください。
では続いて「読み書き両用」パターンのオーバーロードを追加してみましょう。
<sample program cpp068-04>
#include <iostream> #include <vector> #include <cstdlib> #include <ctime> class Sample { public: Sample(); void Show() const; int operator[](const unsigned int index) const; int& operator[](const unsigned int index); private: std::vector<int> m_vecInt; }; int main() { Sample sample; sample.Show(); sample[0] = 12; std::cout << sample[0] << std::endl; return 0; } Sample::Sample() { srand((unsigned int)time(NULL)); int count = rand() % 6 + 5; for (int i = 0; i < count; i++) { m_vecInt.push_back((i + 1) * 10); } } void Sample::Show() const { for (unsigned int i = 0; i < m_vecInt.size(); i++) { std::cout << m_vecInt[i] << " "; } std::cout << std::endl; } int Sample::operator[](const unsigned int index) const { return m_vecInt[index]; } int& Sample::operator[](const unsigned int index) { return m_vecInt[index]; } |
<実行結果>
10 20 30 40 50 60 70 12 続行するには何かキーを押してください・・・
これもプロトタイプ宣言から見てみましょう。
int& operator[](const unsigned int index); |
引数は添え字(インデックス)ですが、戻り値はint型の参照です。
本体を見ても、配列の指定した要素の参照を返しています。
main関数を見てみると、
sample[0] = 12; |
あたかも、配列の要素に数値を代入しているように見えます。
しかし、=演算子の左辺は「配列の指定した要素の参照」です。
右辺の数値が「配列の指定した要素」へ代入されている事が分かります。