C++編で扱っている C++ は 2003年に登場した C++03
という、とても古いバージョンのものです。C++ はその後、C++11 -> C++14
-> C++17 -> C++20 -> C++23 と更新されています。
なかでも C++11 での更新は非常に大きなものであり、これから C++
の学習を始めるのなら、C++11
よりも古いバージョンを対象にするべきではありません。特に事情がないなら、新しい
C++ を学んでください。 当サイトでは、C++14 をベースにした新C++編を作成中です。
問題① 第26章の練習問題で、標準ライブラリの bitset(【標準ライブラリ】第13章)に、すべてのビットが 1 になっているかどうかを判定するメンバ関数を、公開継承を使って追加するという題材を扱いました。同様のことを、普通の合成、非公開継承、限定公開継承のそれぞれを使って行ってください。
まず、普通の合成を使った手法です。
#include <iostream>
#include <bitset>
template <std::size_t BITS>
class MyBitset {
public:
inline bool all() const
{
return mBitset.size() == mBitset.count();
}
inline void set()
{
.set();
mBitset}
inline void set(std::size_t pos, bool val = true)
{
.set(pos, val);
mBitset}
private:
std::bitset<BITS> mBitset;
};
int main()
{
<10> bset;
MyBitset
.set();
bsetstd::cout << std::boolalpha << bset.all() << std::endl;
.set(0, false);
bsetstd::cout << std::boolalpha << bset.all() << std::endl;
}
目的のメンバ関数を実装すること自体はとても簡単ですが、大きな問題があります。それは、std::bitset が持つ「公開」メンバを、MyBitsetクラスの外部からは使用できないことです。外部から呼び出せるようにするには、MyBitset側で同等のメンバを用意して、bitset のメンバへ転送する必要があります。上のサンプルプログラムでは、setメンバ関数だけを用意しましたが、bitset のすべてのメンバに対して同じことをするのは、非常に面倒ですし、厳密に同じ関数を宣言するのも意外と大変です。
普通の合成での面倒な部分をある程度回避できるのが、非公開継承を使った実装です。
#include <iostream>
#include <bitset>
template <std::size_t BITS>
class MyBitset : private std::bitset<BITS> {
public:
using std::bitset<BITS>::set;
inline bool all() const
{
return size() == count();
}
};
int main()
{
<10> bset;
MyBitset
.set();
bsetstd::cout << std::boolalpha << bset.all() << std::endl;
.set(0, false);
bsetstd::cout << std::boolalpha << bset.all() << std::endl;
}
の場合は、using を使って、その名前をスコープに取り込めます。上のサンプルプログラムで言えば、bitset のスコープにあった set が、今や MyBitset のスコープにあるということです。また、using は「公開」の場所に書いているので、set はきちんと「公開」されます。これでも、bitset のすべてのメンバを1つ1つ using していく必要はありますが、転送関数を作成していくよりは、ずっとましです。
最後に、限定公開継承を使った実装です。
#include <iostream>
#include <bitset>
template <std::size_t BITS>
class MyBitset : protected std::bitset<BITS> {
public:
using std::bitset<BITS>::set;
inline bool all() const
{
return size() == count();
}
};
int main()
{
<10> bset;
MyBitset
.set();
bsetstd::cout << std::boolalpha << bset.all() << std::endl;
.set(0, false);
bsetstd::cout << std::boolalpha << bset.all() << std::endl;
}
これは、非公開継承の場合とまったく同じです。本編で触れたように、限定公開継承のポイントは、さらなる派生クラスから、基底クラスの「公開」「限定公開」メンバをアクセスできることです。したがって、MyBitsetクラスから派生させるつもりがないのなら、限定公開継承を使う理由も無く、非公開継承を使えば良いです。
一方、MyBitsetクラスから派生させるのなら、派生クラスから bitset のメンバをアクセスできることは利点になります。
template <std::size_t BITS>
class MyBitset2 : public MyBitset<BITS> {
public:
// 先頭と末尾のビットが同じ値か
inline bool is_equal_head_and_tail() const
{
return test(0) == test(size() - 1);
}
};
is_equal_head_and_tailメンバ関数内で、bitset の testメンバ関数や sizeメンバ関数を呼び出しています。このように、さらなる派生クラスのメンバ関数内からは、限定公開継承の基底になっている std::bitset の「公開」「非公開」メンバを呼び出せます。
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |