改・スマートポインタテンプレートクラス(ダウンキャストサポート)
@ ダウンキャストの実装
前章までのスマートポイントはアップキャストまでをサポートしました。このままでも十分に実用に耐えますが、さらに機能を充実し、ポインタとしての振る舞いを再現するため、ダウンキャストの実装をします。と言っても、実装は簡単です。
ダウンキャストはC++から追加されたdynamic_cast演算子を用います。簡単な例は次の通りです。
class Animal
{public: virtual void MyName(){cout << "Animal" << endl;} };
class Human : public Animal
{
private:
string m_Name;
public:
virtual void MyName(){cout << m_Name.c_str() << endl;}
void SetName(string name){ m_Name = name;}
};
main(){
Animal *animal = new Animal;
Human *human = new Human;
Animal = human; // アップキャスト
// ダウンキャスト
Human *IKD = dynamic_cast<Human*>(Animal);
if(IKD){
IKD->SetName("IKD");
IKD->MyName();
}
}
なかなか良い例が作れないのですが・・・ダウンキャストは親ポインタが元々子ポインタだった場合に成功し、子ポインタのメンバ変数や関数にアクセスできるようになります。「親オブジェクトを子オブジェクトに無理やりすることはできません」。これをスマートポインタに対しても出来るようにします。
実装は次の通りです。
SmartPtr.h template <class T>
class sp
{
////////////////////
// ダウンキャスト
/////
template <class T2>
sp<T> DownCast(sp<T2> &src)
{
// 引数のスマートポインタが持つポインタが、
// 自分の登録しているポインタに
// ダウンキャスト可能な場合はオブジェクトを返す
T* castPtr = dynamic_cast<T*>(src.GetPtr());
if(castPtr != NULL){
// ダウンキャスト成功
// キャストされたポインタを含む新しい
// スマートポインタを作ることになるので、
// 参照カウンタをセットする
sp<T> tmp(castPtr, *src.GetRefPtr() + 1);
return tmp;
}
// キャスト失敗
sp<T> tmp(NULL, 1);
return tmp;
}
};
これはテンプレート関数です。T2型のポインタを保持しているスマートポインタをT型のスマートポインタにダウンキャストします。成功した場合はcastPtrにsrc.GetPtrと同じアドレスを持つポインタ(ダウンキャスト済み)が返りますので、新しいスマートポインタに登録して返します。この時、参照カウンタは同じポインタを指している数+1にします。「+1」は関数の外に出る時に減りすぎる分をカバーします。
前章までのスマートポインタに上のDownCast関数部分を挿入すると、ダウンキャストをサポートしたスマートポインタが出来上がります!
(今回は短い章で終わりましたが大きな一歩です(^^;)