我在做编译器项目的时候, 我们采用c++语言,但要使用多态的性质,一是用引用,二是用指针。可是引用不够灵活,指针还具有内存管理问题。所以SmartPtr是一个必然的选择,可我发现通常的SmartPtr不能够支持多态,原因是编译器只能进行一次类型转换,如SmartPtr->裸指针,但裸指针到他的基类指针不会自动转换。本篇将实现一个支持多态的智能指针,没什么技术含量,大家不要见笑。
原理:既然SmartPtr->裸指针->基类指针的自动转换不可能,那么变一个方式
SmartPtr<Derived> -> SmartPtr<Base> -> Base.这就要求SmartPtr<Derived>与SmartPtr<Base>之间的继承结构要与Derived与Base之间的继承结构相同。好,让我们写一个吧。
//File:SmartPtr.h
#ifndef CMM_TOOL_TSMART_PTR_H_
#define CMM_TOOL_TSMART_PTR_H_
//所有类的基类,这个类只是为了统一智能指针的用法,下面会看到
class GlobalBaseObject
{
public:
virtual ~GlobalBaseObject()
{
}
};
//是所有智能指针的基类,提供了一些方法如下:
class GlobalBaseObjectPtr
{
protected:
//释放智能指针
void _Release()
{
if(pOri && --*pRef == 0){
delete pOri;
delete pRef;
}
}
//加一个引用计数
void _SafeAdd()
{
if(pRef)--*pRef;
}
//这个析构函数使得任何继承这个类的智能指针不需要定义析构函数,
//因为智能指针释放指针时只需要一次析构
~GlobalBaseObjectPtr()
{
_Release();
}
//之所以使用void*,是为了原始数据类型也可以使用智能指针
void* pOri;
//引用计数
int* pRef;
};
template <typename T,typename B/*是T类型的基类的智能指针类*/>
class SmartPtr : public B
{
public:
SmartPtr<T,B>()
{
pOri = NULL;
pRef = NULL;
}
explicit SmartPtr<T,B>(T* oriPtr){
pOri = (void*)oriPtr;
pRef = NULL;
if(pOri)pRef = new int(1);
}
SmartPtr<T,B>(const SmartPtr<T,B>& other){
pOri = (void*)other.pOri;
pRef = other.pRef;
_SafeAdd();
}
SmartPtr<T,B>& operator =(const SmartPtr<T,B>& other){
if(pOri != other.pOri){
_Release();
pOri = (void*)other.pOri;
pRef = other.pRef;
_SafeAdd();
}
return (*this);
}
T * operator ->(){
return (T*)pOri;
}
operator T *(){
return (T*)pOri;
}
/*
注:不可以定义析构函数,也不需要,因为基类已经实现
*/
};
//为了使用方便定义了两个宏
#define DeclareSmartPtr(dClass,baseClass) typedef SmartPtr< dClass , baseClass##Ptr > dClass##Ptr;
#define BaseSmartPtr(dClass) typedef SmartPtr< dClass ,GlobalBaseObjectPtr> dClass##Ptr;
#endif
使用方法如下:
class Symbol : public GlobalBaseObject
{
public:
virtual bool Match(Token* token) = 0;
protected:
int id;
};
class Token : public Symbol
{
public:
virtual bool Match(Token* token);
};
class NonToken : public Symbol
{
public:
virtual bool Match(Token* token);
};
class Reserved : public Token
{
public:
bool Match(Token* token);
};
BaseSmartPtr(Symbol)
BaseSmartPtr(int)
DeclareSmartPtr(Token,Symbol)
DeclareSmartPtr(NonToken,Symbol)
DeclareSmartPtr(Reserved,Token)
int main()
{
TokenPtr symb = TokenPtr(new Token);
SymbolPtr symb1 = NonTokenPtr(new NonToken);
TokenPtr symb2 = ReservedPtr(new Reserved);
cout<<boolalpha<<symb1->Match(symb)<<endl<<symb1->Match(symb2)<<endl;
SymbolStack st;
st.push(symb);
st.push(symb1);
SymbolPtr symbTemp = st.top();
cout<<symbTemp->Match(symb2)<<endl;
st.pop();
symbTemp = st.top();
cout<<symbTemp->Match(symb2)<<endl;
intPtr pt = intPtr(new int(12));
cout<<*pt<<endl;
return 0;
}