【Effective C++】オブジェクト間の複合関係——has aおよびis-implemented-in-terms-of
ふくごうかんけい
あるタイプのオブジェクトに他のタイプのオブジェクトが含まれている場合、それらの間にはこのような複合関係があります.例:
ここで例として、
has-aおよびis-implemented-in-tems-of
前に述べたように、public継承はis-aの関係を意味する.複合には、対応する意味もあり、2つの意味があります.複合はhas−aまたはis−implemented−in−terms−ofを意味する.上のPerson classはhas-aの関係です.面倒なのはis-aとis-implemented-in-terms-ofの関係を区別することです.
たとえば、重複しないオブジェクトからなるコンテナを実装するためにテンプレートクラスを書く必要があります.あなたの最初の反応は、stlで提供されているstd::set容器を直接使用していました.しかし、このコンテナの背後には赤と黒の木があり、検索、挿入、削除の速度は対数レベルですが、各要素には3つのポインタの追加オーバーヘッドがあります.空間で時間を変えたくないので、自分で別のテンプレートクラスを実現したいと思っています.考えた上で、トップレベルでstlのstd::listでstd::setの機能を実現することにしました.std::listを呼び出すには.もちろん2つの実装形式があります.1つ目はそれを継承することです.そうすれば、そのメンバーを得ることができます.または、そのオブジェクトまたはポインタを含むオブジェクトまたはポインタで、そのオブジェクトまたはポインタを介してメンバーを呼び出します.最初の方法を採用する場合は、
美しく見えますが、実はそうではありません.以前にも繰り返し述べたように,public継承はis−aの関係を意味し,ベースクラスにとっていかなる有意義な行為もサブクラスにとって有意義である必要がある.しかしここでは、
ここでの
あるタイプのオブジェクトに他のタイプのオブジェクトが含まれている場合、それらの間にはこのような複合関係があります.例:
class Address { //... };
class PhoneNumber { //... };
class Person
{
public:
//...
private:
std::string name;
Address address;
PhoneNumber voiceNumber;
PhoneNumber faxNumber;
};
ここで例として、
Person
対象はstd::string
、Address
、PhoneNumber
を複合したものとする.has-aおよびis-implemented-in-tems-of
前に述べたように、public継承はis-aの関係を意味する.複合には、対応する意味もあり、2つの意味があります.複合はhas−aまたはis−implemented−in−terms−ofを意味する.上のPerson classはhas-aの関係です.面倒なのはis-aとis-implemented-in-terms-ofの関係を区別することです.
たとえば、重複しないオブジェクトからなるコンテナを実装するためにテンプレートクラスを書く必要があります.あなたの最初の反応は、stlで提供されているstd::set容器を直接使用していました.しかし、このコンテナの背後には赤と黒の木があり、検索、挿入、削除の速度は対数レベルですが、各要素には3つのポインタの追加オーバーヘッドがあります.空間で時間を変えたくないので、自分で別のテンプレートクラスを実現したいと思っています.考えた上で、トップレベルでstlのstd::listでstd::setの機能を実現することにしました.std::listを呼び出すには.もちろん2つの実装形式があります.1つ目はそれを継承することです.そうすれば、そのメンバーを得ることができます.または、そのオブジェクトまたはポインタを含むオブジェクトまたはポインタで、そのオブジェクトまたはポインタを介してメンバーを呼び出します.最初の方法を採用する場合は、
template<typename T>
class MySet : public std::list<T> { //... }
美しく見えますが、実はそうではありません.以前にも繰り返し述べたように,public継承はis−aの関係を意味し,ベースクラスにとっていかなる有意義な行為もサブクラスにとって有意義である必要がある.しかしここでは、
std::list
同じデータを持つことができますが、MySet
できません.だから、MySetはstd::listは本当ではありません.std::listが本当であるものはMySetにとって本当ではないからです.正しい方法は、MySetにstd::listオブジェクトを含めることです.template <typename T>
class MySet
{
public:
bool member(const T& item) const;
void insert(const T& item);
void remove(const T& item);
std::size_t size() const;
private:
std::list<T> rep;
};
template<typename T>
bool MySet<T>::member(const T& item) const
{
return std::find(rep.begin(), rep.end(), item) != rep.end();
}
template<typename T>
void MySet<T>::insert(const T& item)
{
if(!member(item))
rep.push_back(item);
}
template<typename T>
void MySet<T>::remove(const T& item)
{
typename std::list<T>::iterator it = std::find(rep.begin(), rep.end(), item);
if(it != rep.end())
rep.erase(it);
}
template<typename T>
std::size_t MySet<T>::size() const
{
return rep.size();
}
ここでの
MySet
とstd::list
はis-implemented-in-terms-ofの関係です.