C++智能指针与类继承多态

时间:2023-01-12 21:58:00

我在做编译器项目的时候, 我们采用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;
}