続いては添字演算子のオーバーロードについて説明します。
添字演算子とは「[ ]」です。
配列の添え字として使いますが、これをオーバーロードするとクラスが配列のように扱えます。
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; |
あたかも、配列の要素に数値を代入しているように見えます。
しかし、=演算子の左辺は「配列の指定した要素の参照」です。
右辺の数値が「配列の指定した要素」へ代入されている事が分かります。