アフィリエイト広告を利用しています

広告

posted by fanblog

2018年01月06日

《その222》 例外用の入れ子クラス



 例外用の入れ子クラス

 次のプログラムは、新版明解C++中級編にあるサンプルプログラムを少し改変して、それに注釈を書き加えたものです。
例外に関する事項以外にもいろいろな復習ができると思い、自分用のメモ的なことを付け足してあるので、かなり読みづらいと思います。
 そのため、プログラム全体を見通せるように、注釈を抜いてプログラムコードだけにしたものを、最後に載せてあります。

 クラス IntArray は、整数配列用のクラスです。例えば、
   int a(20);
のような記述で、要素数 20 の整数配列を定義します。各要素には、a[0] 〜 a[19] でアクセスします。
また、コピーコンストラクタを使うときは、
   IntArray b(a); や  IntArray b = a;
のように記述します。

 クラス IntArray は、不正な添字でアクセスがあった場合に使う例外通知用の入れ子クラス IdxRngErr を持っています。

// ------------------------------------
#ifndef ___Class_IntArray
#define ___Class_IntArray

// IntArray.h

// ◆整数配列クラス

class IntArray {
int nelem; // 配列の要素数
int* vec; // 配列の先頭要素へのポインタ

bool is_valid_index(int idx) const {
return idx >= 0 && idx < nelem;
// 配列の添字が 0以上 nelem未満なら trueを返します。
}

public:
// ◆添字範囲エラークラス(入れ子クラス)
class IdxRngErr {
private:
const IntArray* ident;
// 例外を送出したオブジェクトへのポインタ。

int idx;
// 例外送出の原因となった、不当な添字の値。

public:
// ◆入れ子クラスのコンストラクタ
IdxRngErr(const IntArray* p, int i)
: ident(p), idx(i) { }

// ◆idx のゲッタ
int index() const { return idx; }
};

// ◆明示的コンストラクタ
// explicit の指定により、コンストラクタが =形式で起動
//          するのを抑止しています。
// (例) IntArray a = 6; ← 不可
// IntArray a(6); ← 可

explicit IntArray(int size) : nelem(size) {
vec = new int[nelem];
// 配列用の領域を動的確保。
}

// ◆コピーコンストラクタ
IntArray(const IntArray& x) {
if (&x == this) {
// 受け取った仮引数 x が自分自身への参照の場合。
nelem = 0;
vec = NULL;
}
else {
nelem = x.nelem;
// そうでない場合。要素数 nelem を、x と同じ値
// にします。


vec = new int[nelem];
// 要素数 nelem の int型配列用領域を動的に確保。

for (int i = 0; i < nelem; i++)
vec[i] = x.vec[i];
// 全要素をコピーします。
}
}

// ◆デストラクタ
~IntArray() { delete[] vec; }
// 動的に確保した配列用の領域を解放します。

// ◆nelem のゲッタ
int size() const { return nelem; }
// 配列の要素数を返します。

// ◆代入演算子

IntArray& operator=(const IntArray& x)
{
if (&x != this) {
// 仮引数 x が自分自身への参照ではない場合。

if (nelem != x.nelem) {
delete[] vec;
nelem = x.nelem;
vec = new int[nelem];
// 自身の要素数 nelemと xの要素数 x.nelem
// が異なる場合は、自身の配列領域
// を解放して、
// x と同じ大きさの領域を動的に確
// 保します。

}

for (int i = 0; i < nelem; i++)
vec[i] = x.vec[i];
// 全要素をコピーします。
}
return *this;
}

// ◆添字演算子[]
int& operator[](int i) {
if (!is_valid_index(i))
throw IdxRngErr(this, i);
// 添字の値が不正ならば、添字範囲エラーを送出。
return vec[i];
}

// ◆const添字演算子[]
// IntArray型オブジェクトが const である場合に使います。

const int& operator[](int i) const {
if (!is_valid_index(i))
throw IdxRngErr(this, i);
return vec[i];
}
};

#endif
// ------------------------------------

// ------------------------------------
// IntArrayTest.cpp
#include <iostream>
#include "IntArray.h"
using namespace std;

void set_and_disp(int size, int num) {
// size … 配列の要素数(大きさ)
// num … 配列の添字 0 〜 num-1 の要素に値をセット


try {
IntArray x(size);
// IntArray型の配列 x を生成(大きさ size)

for (int i = 0; i < num; i++) {
x[i] = i + 10;
// x[i] に値 i+10 を代入
// x[0]=0+10, x[1]=1+10, x[2]=2+10, ・・
// ・・ ,x[num-1] = num-1+10


cout << "x[" << i << "] = "
<< x[i] << '\n';
// 作成した配列の num個の配列要素を表示。
}
}

catch (const bad_alloc&) {
// IntArray型配列用領域の動的確保に失敗した場合
// の例外ハンドラ。

cout << "メモリの確保に失敗しました。\n";
exit(1);
}

catch (const IntArray::IdxRngErr& x) {
// 配列の最大添字を超える値の添字を使って、配列
// 要素にアクセスしようとした場合
// に送出される IntArray型オブジェ
// クトを受け取る例外ハンドラ。


cout << "添字オーバフロー:" << x.index()
<< '\n';
// index() … 例外情報クラス IdxRngErr のメ
// ンバ関数 index は、例外送出の
// 原因となった添字の値を返す。

return;
}
}

int main()
{
int size, num;
// size … 作成する IntArray型配列の要素数。
// num … 作成した配列の添字 0 〜 num-1 の要素
// に値をセット。


cout << "要素数 : "; cin >> size;
cout << "データ数 : "; cin >> num;
set_and_disp(size, num);

cout << '\n';
IntArray a(6);
// 配列 a を生成(要素数 6)

for (int i = 0; i < 6; i++)
a[i] = i + 100;
const IntArray(b) = a;
for (int i = 0; i < 6; i++)
cout << b[i] << ' ';
// const添字演算子[] を多重定義してあるので、
// b に対して添字演算子 [] が使えます。

cout << '\n';
}
// ------------------------------------

f08_0005.png
f08_0006.png



 以下は、上記のプログラムから注釈を取り除いたものです。プログラム自体は、同じものです。

// ------------------------------------
#ifndef ___Class_IntArray
#define ___Class_IntArray

// IntArray.h

// ◆整数配列クラス

class IntArray {
int nelem;
int* vec;
bool is_valid_index(int idx) const {
return idx >= 0 && idx < nelem;
}

public:
// ◆添字範囲エラークラス(入れ子クラス)
class IdxRngErr {
private:
const IntArray* ident;
int idx;
public:
IdxRngErr(const IntArray* p, int i)
: ident(p), idx(i) { }

int index() const { return idx; }
};

// ◆明示的コンストラクタ
explicit IntArray(int size) : nelem(size) {
vec = new int[nelem];
}

// ◆コピーコンストラクタ
IntArray(const IntArray& x) {
if (&x == this) {
nelem = 0;
vec = NULL;
}
else {
nelem = x.nelem;
vec = new int[nelem];
for (int i = 0; i < nelem; i++)
vec[i] = x.vec[i];
}
}

// ◆デストラクタ
~IntArray() { delete[] vec; }

int size() const { return nelem; }

// ◆代入演算子
IntArray& operator=(const IntArray& x)
{
if (&x != this) {
if (nelem != x.nelem) {
delete[] vec;
nelem = x.nelem;
vec = new int[nelem];
}

for (int i = 0; i < nelem; i++)
vec[i] = x.vec[i];
}
return *this;
}

// ◆添字演算子[]
int& operator[](int i) {
if (!is_valid_index(i))
throw IdxRngErr(this, i);
return vec[i];
}

// ◆const添字演算子[]
const int& operator[](int i) const {
if (!is_valid_index(i))
throw IdxRngErr(this, i);
return vec[i];
}
};

#endif
// ------------------------------------

// ------------------------------------
// IntArrayTest.cpp
#include <iostream>
#include "IntArray.h"
using namespace std;

void set_and_disp(int size, int num) {
try {
IntArray x(size);

for (int i = 0; i < num; i++) {
x[i] = i + 10;
cout << "x[" << i << "] = "
<< x[i] << '\n';
}
}

catch (const bad_alloc&) {
cout << "メモリの確保に失敗しました。\n";
exit(1);
}

catch (const IntArray::IdxRngErr& x) {
cout << "添字オーバフロー:" << x.index()
<< '\n';
return;
}
}

int main()
{
int size, num;

cout << "要素数 : "; cin >> size;
cout << "データ数 : "; cin >> num;
set_and_disp(size, num);

cout << '\n';
IntArray a(6);
for (int i = 0; i < 6; i++)
a[i] = i + 100;
const IntArray(b) = a;
for (int i = 0; i < 6; i++)
cout << b[i] << ' ';
cout << '\n';
}
// ------------------------------------


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/11/10 13:13時点)

新版 明解C 中級編 (明解シリーズ)

新品価格
¥2,916から
(2017/11/10 13:14時点)





この記事へのコメント
コメントを書く

お名前:

メールアドレス:


ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバックURL
https://fanblogs.jp/tb/7165200
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


検索
<< 2018年08月 >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
プロフィール
こうすけさんの画像
こうすけ

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


×

この広告は30日以上新しい記事の更新がないブログに表示されております。