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

広告

posted by fanblog

2017年12月16日

《その180》 継承と静的メンバ & p.174演習4-4


 継承と静的メンバ

 静的メンバを含むクラスから派生した子クラスは、親クラスである基底クラスの静的メンバを、そのまま静的メンバとして継承します。
次のプログラムで、その様子が確認できます。

 親クラス型のオブジェクト,子クラス型のオブジェクト,孫クラス型のオブジェクトが、それぞれのオブジェクト型とは無関係に、作成された順にマイナンバー my_num を割り当てられています。

// ------------------------------------
#include <iostream>

class Num {
static int num;
// Num型のオブジェクトを作成した個数を記録する
// ための静的データメンバです。


int my_num;
// 各オブジェクト自身が、何番目に作られたもので
// あるか、オブジェクト作成時にその
// 値で初期化されます。


public:
Num() : my_num(++num) { }
// コンストラクタ
// オブジェクトを作成する毎に、num の値をイ
// ンクリメントし、
// その値で、各オブジェクトの my_num を初期
// 化します。


void my_n() const {
std::cout << my_num << '\n';
}
// my_num のゲッタです。
};

/* public派生した子クラス */
class Aaa : public Num {
int a;
public:
Aaa(int x = 1000) : a(x) { }
int get_a() { return a; }
};

/* public派生した孫クラス */
class Bbb : public Aaa {
int b;
public:
Bbb(int x = 2000) : b(x) { }
int get_b() { return b; }
};

int Num::num = 0;

int main()
{
Num n1; // 1個目の Num型オブジェクト
n1.my_n(); // 1

Num n2; // 2個目の Num型オブジェクト
n2.my_n(); // 2

Aaa a1; // 1個目の Aaa型オブジェクト
a1.my_n(); // 3

Aaa a2; // 2個目の Aaa型オブジェクト
a2.my_n(); // 4

Bbb b1; // 1個目の Bbb型オブジェクト
b1.my_n(); // 5

Num n3; // 3個目の Num型オブジェクト
n3.my_n(); // 6
}
// ------------------------------------

f04_0010.png



新版明解C++中級編 p.174 演習4-4
 次のクラス ResigningMember へのポインタからクラス Member へのポインタへのアップキャストが行えるかどうか、プログラムを作成して確認せよ。

// ------------------------------------
/* 一般会員クラス Member */
class Member {
std::string full_name; // 氏名
int number; // 会員番号
double weight; // 体重

public:
Member(const std::string& name, int no, double w)
: full_name(name), number(no) {
set_weight(w); // 体重を設定
}

// full_nameのゲッタ
std::string name() const {
return full_name;
}

// numberのゲッタ
int no() const { return number; }

// weightのゲッタ
double get_weight() const {
return weight;
}

// weightのセッタ
void set_weight(double w) {
weight = (w > 0) ? w : 0;
}
};

/* 退会済み会員クラス ResigningMember */
class ResigningMember : private Member {
public:
ResigningMember(
const std::string& name,
int number,
double w
) : Member(name, number, w) { }

// weightのゲッタを再定義
double get_weight() {
std::cout
<< "退会した会員の体重の"
"取得はできません。\n";
return 0;
}

using Member::no; // using宣言
};
// ------------------------------------

◆以下が解答のプログラムです。

// p174_演習4-4
#include <string>
#include <iostream>

/* 一般会員クラス MeMber */
class Member {
std::string full_name; // 氏名
int number; // 会員番号
double weight; // 体重

public:
Member(const std::string& name, int no, double w)
: full_name(name), number(no) {
set_weight(w); // 体重を設定
}

// full_nameのゲッタ
std::string name() const {
return full_name;
}

// numberのゲッタ
int no() const { return number; }

// weightのゲッタ
double get_weight() const {
return weight;
}

// weightのセッタ
void set_weight(double w) {
weight = (w > 0) ? w : 0;
}
};

/* 退会済み会員クラス ResigningMember */
class ResigningMember : private Member {
public:
ResigningMember(
const std::string& name,
int number,
double w
) : Member(name, number, w) { }

// weightのゲッタを再定義
double get_weight() { // ★2.
std::cout
<< "退会した会員の体重の"
"取得はできません。\n";
return 0;
}

using Member::no; // using宣言★1.
};

int main()
{
ResigningMember oosugi("大杉毬藻", 26, 50.7);

//// Member* ptr1 = &oosugi; // ← エラー
// [コンパイラからのメッセージ]
// (1) アクセスできない基底クラス "Member"
// への変換は許可されていません。
// (2) '型キャスト': 'ResigningMember *'
// から'Member *'の変換は存在し
// ますが、アクセスできません。


ResigningMember* ptr2 = &oosugi; ////

std::cout << "会員番号 : "
<< ptr2->no() << '\n';
// ★1.印のusing宣言により、アクセス権あり。

// cout << "氏名 : " << oosugi.name()
// << '\n'; // ← エラー

std::cout << "体重 : "
<< ptr2->get_weight() << '\n';
// ★2.印の再定義により、元々の get_weight
// は隠蔽され、再定義され
// た get_weight が呼ばれ
// る。

// oosugi.set_weight(45.3); // ← エラー

/*
上の印の結果によれば、クラス ResigningMember
へのポインタからクラス Member へのポインタへの
アップキャストは、行えない、と言えます。
*/



// ************ 以上が解答です ************
// ************ 以下は付け足し ************

/*
上のプログラムの、印のようなやり方で、直接的
に、Resigning型オブジェクトである oosugi へのポイ
ンタを、Member*型の変数 ptr1 に代入しようとする
アップキャストは、エラーになります。

そこで、一旦、上のプログラムの印にもあるような、

ResigningMember* ptr2 = &oosugi;
という、問題のない方法で ResigningMember*型の
ポインタ ptr2 を作成した上で、そのポインタを次のよう
にアップキャストしてみます。

Member* ptr3 = (Member*)ptr2;

このようにして作成したポインタ ptr3 を使用する
と、次のようなアクセスが可能になります。
すなわち、
派生クラスオブジェクト oosugi の中に
基底クラス部分オブジェクトとして存在する基底クラスオブ
ジェクトMember のメンバ関数 get_weight() に、アク
セスできるようになります。

つまり、

std::cout << ptr3->get_weight() << '\n';
が、可能になります。
*/


std::cout << "\n以下は、付け足しです。\n";

Member* ptr3 = (Member*)ptr2;
std::cout << ptr3->get_weight() << '\n';
}

f04_04.png


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

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

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

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





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

お名前:

メールアドレス:


ホームページアドレス:

コメント:

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

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

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

 たまに、クリック お願いします 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日以上新しい記事の更新がないブログに表示されております。