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

広告

この広告は30日以上更新がないブログに表示されております。
新規記事の投稿を行うことで、非表示にすることが可能です。
posted by fanblog

2017年12月11日

《その173》 コピーコンストラクタ,デストラクタ,代入演算子 の継承


 コピーコンストラクタ,デストラクタ,代入演算子 の継承

 基底クラスからの派生によって作成される派生クラスについて、デフォルトコンストラクタ,コピーコンストラクタ,代入演算子が、どのような形で継承されるのかを、下のプログラムで確認してみます。

 ◆ クラス Array を基底クラスとして、public派生により 派生クラス ArrayX を作ります。
 最初に、下のプログラムの説明を書きます。


基底クラス Array について

 配列要素数 num = 5
 p は配列の先頭要素へのポインタ用の変数です。

 char型の chr には、main関数内で作成する クラスオブジェクト a, b, c を識別するために、それぞれ文字 'a', 'b', 'c' を、実行時に代入します。プログラム終了時にクラスオブジェクトが、デストラクタによって破壊される直前に、この文字を表示します。

 Array() は引数無しのデフォルトコンストラクタです。
new int[num] により int型配列用の領域を動的に確保して、その先頭要素のアドレスをポインタ p に代入します。

 Array(const Array& x) はコピーコンストラクタです。
コピー元の配列 int[x.num] と同じ大きさの領域を動的に確保し、そこに、コピー元の配列要素をすべてコピーします。

 ~Array() はデストラクタです。
プログラム終了時に、クラスオブジェクトが破壊されるときに呼ばれます。動的に確保した記憶領域を解放します。また、 'a', 'b', 'c' のいずれかの文字を表示して自分の正体をアピールします。

 Array& operator=(const Array& x) は代入演算子の多重定義です。
代入演算子「=」が、Array型オブジェクトを扱えるようにするための多重定義です。
代入される側のオブジェクトが、自分自身の中に、コピー元の配列 int[x.num] と同じ大きさの領域を動的に確保し、そこに、コピー元の配列要素をすべてコピーします。

 メンバ関数 void set(int v)
配列 p の全要素に値 v を代入します。

 メンバ関数 void print() const
配列 p の全要素の値を表示します。


派生クラス ArrayX について

 クラス Array を親として、public派生により 作成される子クラスです。継承の際は、コンストラクタ,デストラクタ,代入演算子 を定義せず、すべて基底クラス Array の資産を利用するものとします。

 int k は、派生クラス ArrayX独自のデータメンバです。

 void set_k(int x) は、派生クラス ArrayX独自のメンバ関数で、k のセッタです。


// ------------------------------------
#include <iostream>
using namespace std;

class Array { /* ◆基底クラス */
const int num = 5;
int *p;

public:
char chr;
Array() : p(new int[num]) {
cout << "デフォルトコンストラクタ(領域確保)\n";
}
// ↑デフォルトコンストラクタ
// 要素数 num の int型配列用領域を確保


Array(const Array& x) : p(new int[x.num]) {
for (int i = 0; i < num; i++) p[i] = x.p[i];
cout << "コピーコンストラクタ\n";
}
// ↑コピーコンストラクタ

~Array() {
delete[] p;
cout << "デストラクタ, chr … " << chr << '\n';
}
// ↑デストラクタ

Array& operator=(const Array& x) {
cout << "代入演算子\n";
for (int i = 0; i < num; i++)
p[i] = x.p[i];
return *this;
}
// ↑代入演算子


void set(int v) {
for (int i = 0; i < num; i++) p[i] = v;
}
// ↑メンバ関数
// 全要素に値 v を代入


void print() const {
for (int i = 0; i < num; i++) cout << p[i] << ' ';
}
// ↑メンバ関数
// 全要素の値を表示

};


class ArrayX : public Array { /* ◆派生クラス */
int k;
public:
int get_k() const { return k; }
void set_k(int x) { k = x; }
};
// コンストラクタ,コピーコンストラクタ,デストラクタ
// の定義はしていない。


int main() {
ArrayX a; // ArrayX a を作成
/* ↑デフォルトコンストラクタが作動 */
a.set(10); // aの全要素に 10 を代入
a.set_k(99); // a.k に 99 を代入

ArrayX b(a); // ArrayX b を作成(aで初期化)
/* ↑コピーコンストラクタが作動 */


ArrayX c; // ArrayX c を作成
/* ↑デフォルトコンストラクタが作動 */

c = a;
/* ↑代入演算子が作動(aの全要素をcにコピー) */

a.chr = 'a'; b.chr = 'b'; c.chr = 'c';

cout << '\n';
cout << "配列a : "; a.print(); cout << '\n';
cout << " k : " << a.get_k() << '\n';
cout << "配列b : "; b.print(); cout << '\n';
cout << " k : " << b.get_k() << '\n';
cout << "配列c : "; c.print(); cout << '\n';
cout << " k : " << c.get_k() << '\n';
cout << '\n';
}
// ------------------------------------
f04_0004.png

 プログラムの実行結果を見ると・・・、
 派生クラス ArrayX の中では、コピーコンストラクタ,デストラクタ,代入演算子 が定義されていないのですが、基底クラス Array の コピーコンストラクタ,デストラクタ,代入演算子 が、派生クラスに対しても、きちんと動作しているようです。
また、派生クラス独自のデータメンバである k や、ゲッタ get_k(),セッタ set_k() も、期待通りにコピーされています。

派生クラス内で、コピーコンストラクタ,デストラクタ,代入演算子 が定義されなければ、基底クラスのものと実質的に同じ働きをするものが、コンパイラにより自動的に定義されます。
派生クラス ArrayX内で自動的に定義される代入演算子は、次の形式のものです。
  ArrayX& ArrayX::operator=(const ArrayX&);
自動的に定義される コピーコンストラクタ,デストラクタ,代入演算子 は、inline かつ public です。


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

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

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

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






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

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

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

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

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


検索
<< 2017年12月 >>
          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日以上新しい記事の更新がないブログに表示されております。