かつて情報をネットで探したときに、断片的な情報はあるものの、分かりやすいサンプルが見付からなかったのでメモ。
Compositeパターンをshared_ptrで実装するのは、単にポインタをshared_ptrに置き換えるだけだと、循環参照が発生する。
ポイントは2つ。
 1.親(Parent)のポインタはshared_ptrでなくweak_ptrに置き換える
 2.shared_from_thisを使う
以下のコードはc++11以降のstl版だが、c++11以前でもboostで同様の実装が可能。必要なヘッダをincludeすれば”std::”を”boost::”に置き換えるだけでOK。
(説明を短くするために全てheaderに入れている)
まずComponentクラス。
メンバ”parent_”をweak_ptrで保持する。
| 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 32 33 34 35 36 37 38 39 40 41 42 | #include <memory> #include <iostream> // 動作確認用: //--------------------------------------------------------------------------- class Component { //-------------------------------- //  Member and Accessor: //________________________________ private: 	std::weak_ptr<Component>  parent_; public: // ---- get ---- 	std::shared_ptr<Component> 			getParent()const{ return parent_.lock(); } 	bool 	hasParent()const{ return parent_.lock().get() != nullptr; } // ---- set ---- 	void    setParent( const std::shared_ptr<Component>& compo ){ parent_ = compo; } //-------------------------------- //  Constructor: //________________________________ public: 	Component() 		: parent_() 		{} //-------------------------------- //  Destructor: //________________________________ public: 	virtual ~Component(){} //-------------------------------- //  Pure Virtual Method: //________________________________ public: 	virtual void Add( const std::shared_ptr<Component>& compo ) = 0; 	virtual void Remove( const std::shared_ptr<Component>& compo ) = 0; 	// 	virtual void Execute( int depth )	= 0; 	virtual void doExecute()    = 0; }; | 
(Executeは階層構造を出力するだけのテスト用Method) 
つづいてCompositeクラス。
継承元に”std::enable_shared_from_this”を指定するのがポイント。
また”Add”で親をセットする際、”shared_from_this()”を使う。
| 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <vector> #include <algorithm> //--------------------------------------------------------------------------- #include "Component.h" //--------------------------------------------------------------------------- class Composite : public Component,public std::enable_shared_from_this<Composite> { //-------------------------------- //  Member and Accessor: //________________________________ private: 	std::vector<std::shared_ptr<Component>> 			childs_; //-------------------------------- //  Constructor: //________________________________ public: 	Composite() 		: Component(), 		  childs_() 		{} //-------------------------------- //  Override Method: //________________________________ public: 	virtual void Add( const std::shared_ptr<Component>& compo ) 	{ 		if( std::find( childs_.begin(), childs_.end(), compo ) == childs_.end() ) 		{ 			childs_.push_back( compo ); 			compo->setParent( shared_from_this() ); 		} 	} 	virtual void Remove( const std::shared_ptr<Component>& compo ) 	{ 		childs_.erase( remove( childs_.begin(), childs_.end(), compo ), childs_.end() ); 	} 	// 	virtual void Execute( int depth ) 	{ 		for( int i = 0; i < depth; ++i ) 			std::cout << " "; 		doExecute(); 		for( size_t i = 0; i < childs_.size(); ++i ) 		{ 			childs_[i]->Execute( depth + 1 ); 		} 	} }; | 
CompositeのConcreteクラスを2つ作ってみる。ひとつはstd::string, もう一つはintをメンバに持つことにする。
| 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 32 | class ConcreteCompositeA : public Composite { //-------------------------------- //  Member and Accessor: //________________________________ private: 	int val_; //-------------------------------- //  Constructor: //________________________________ public: 	explicit ConcreteCompositeA( int val ) 		: Composite(), 		  val_(val) 		{} //-------------------------------- //  Destructor: //________________________________ public: 	~ConcreteCompositeA(){} //-------------------------------- //  Override Method: //________________________________ public: 	virtual void doExecute() 	{ 		std::cout << "A: val == " << val_ << std::endl; 	} }; | 
| 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 32 33 34 35 36 37 38 39 | #include <string> //--------------------------------------------------------------------------- #include "Composite.h" //--------------------------------------------------------------------------- class ConcreteCompositeB : public Composite { //-------------------------------- //  Member and Accessor: //________________________________ private: 	std::string	str_; public: // ---- set ---- // ---- get ---- //-------------------------------- //  Constructor: //________________________________ public: 	explicit ConcreteCompositeB( const std::string& str ) 		: Composite(), 		  str_(str) 		{} //-------------------------------- //  Destructor: //________________________________ public: 	~ConcreteCompositeB(){} //-------------------------------- //  Override Method: //________________________________ public: 	virtual void doExecute() 	{ 		std::cout << "B: str == " << str_ << std::endl; 	} }; | 
実行してみる。適当に親子関係を作り、出力。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <stdio.h> #include <conio.h> #include "ConcreteCompositeA.h" #include "ConcreteCompositeB.h"  int _tmain(int argc, _TCHAR* argv[]) { 	std::shared_ptr<Component> c1 = std::make_shared<ConcreteCompositeA>( 3 ); 	std::shared_ptr<Component> c2 = std::make_shared<ConcreteCompositeB>( "child" ); 	std::shared_ptr<Component> c3 = std::make_shared<ConcreteCompositeB>( "child of child" ); 	std::shared_ptr<Component> c4 = std::make_shared<ConcreteCompositeA>( 107 ); 	std::shared_ptr<Component> c5 = std::make_shared<ConcreteCompositeB>( "other child" ); 	c3->Add( c4 ); 	c2->Add( c3 ); 	c1->Add( c2 ); 	c1->Add( c5 ); 	c1->Execute( 0 ); 	getch(); 	return 0; } | 
出力結果。
—————————————-
A: val == 3
 B: str == child
  B: str == child of child
   A: val == 107
 B: str == other child
—————————————-
生ポインタを使うのと比べ、解放処理が不要で便利。
