Sunday, February 20, 2005
A tutorial for smart pointer and operator overload
#include <iostream>
using namespace std;
class sp1
{
public:
int data;
sp1* operator ->() { return this;};
//overload "->" operator "." can not be overloaded
};
//a data object that can be reference to a user data object, and count the references
//to it, and increment and decrement the reference counter.
// this class is used internally by smart pointer class CPtr
template<typename T>
class CDataPacket
{
private:
int RefNum;
public:
T* pData;
CDataPacket();
~CDataPacket();
void DecRef();
void IncRef();
};
template<typename T>
void CDataPacket<T>::DecRef()
{
if (RefNum == 0) return;
RefNum--;
if (RefNum == 0)
delete this;
}
template<typename T>
void CDataPacket<T>::IncRef()
{
RefNum++;
}
template<typename T>
CDataPacket<T>::CDataPacket()
{
pData = NULL;
RefNum = 0;
}
template<typename T>
CDataPacket<T>::~CDataPacket()
{
delete pData;
}
//////////////////smart pointer////////////
template<typename T>
class CPtr
{
private:
CDataPacket<T> * Refs;
public:
~CPtr();
CPtr();
T* operator->();
T & operator*();
operator T*();
CPtr<T>& operator = ( T* p);
CPtr<T>& operator = ( CPtr<T>& p);
};
// scenario
// T* p = new <T>
// CPtr p_self = p;
//processing
// decrease the reference number on the DataPacket Refs if it exists
// if the reference number of Refs becomes zero, it will be garbage-collected
// create a new DataPacket with the value p
// increate the reference number on the new DataPacket
template<typename T>
CPtr<T>& CPtr<T>::operator= ( T* p)
{
cout<< "overload CPtr<T>& CPtr<T>::operator= ( T* p)" <<endl;
if (Refs) Refs->DecRef();
Refs = new CDataPacket<T>
Refs->pData = p;
Refs->IncRef();
return *this;
}
//scenario
// CPtr<T> p_self;
// CPtr<T> p;
// p_self = p;
//processing: the same as above
template<typename T>
CPtr<T>& CPtr<T>::operator= ( CPtr<T>& p)
{
cout<< "overload CPtr<T>& CPtr<T>::operator= ( CPtr<T>& p) " <<endl;
if ( Refs)
Refs->DecRef();
Refs = p.Refs;
Refs->IncRef();
return *this;
}
//scenario
// CPtr<T> p_self = new <T>
// delete p_self;
//processing: the same as above
template<typename T>
CPtr<T>::~CPtr()
{
Refs->DecRef();
}
//scenario
// CPtr<T> p_self = new <T>
//processing
// no DataPacket is assigned, so set it to NULL
template<typename T>
CPtr<T>::CPtr()
{
Refs = NULL;
}
//scenario
// CPtr<T> p_self = new <T>
// p_self->XXX
//processing
// return the pointer to actural data
template<typename T>
T* CPtr<T>::operator ->()
{
cout<< "overload T* CPtr<T>::operator ->()" <<endl;
return Refs->pData;
}
//scenario
// CPtr<T> p_self = new <T>
// (*p_self).XXX
//processing
// return the actural data
template<typename T>
T& CPtr<T>::operator *()
{
cout<< "overload T& CPtr<T>::operator *()" <<endl;
return *(Refs->pData);
}
// CPtr<T> p_self = new <T>
// p_self[0] = <T> a;
//processing
// return the pointer to actural data
template<typename T>
CPtr<T>::operator T*()
{
cout<< "overload CPtr<T>::operator T*()" <<endl;
return Refs->pData;
}
/////////////Testing Class///////////////
class test
{
private:
int data;
public:
test(int i){ data = i;};
~test(){ cout << " class #"<<data<<" destroyed."<< endl; };
void DoSomeThing(){ cout << " class #"<<data<<" doing something."<< endl; };
};
int main()
{
//test 1: sp1 overload ->
sp1 t;
cout << "input a number" <<endl;
cin >> t.data;
cout << t->data <<endl;
//test2: CPtr overload
CPtr<int> pii;
pii = new int[10]; //overload CPtr<T>& CPtr<T>::operator= ( T* p)
pii[0]=0; //overload CPtr<T>::operator T*()
pii[2]=10; //overload CPtr<T>::operator T*()
cout << pii[0] << endl; //overload CPtr<T>::operator T*()
cout << pii[2] << endl; //overload CPtr<T>::operator T*()
//test3: test class
CPtr<test> ts0,ts1,ts2;
ts0 = new test(0); // overload CPtr<T>& CPtr<T>::operator= ( T* p)
ts1 = new test(1); // overload CPtr<T>& CPtr<T>::operator= ( T* p)
ts2 = new test(2); // overload CPtr<T>& CPtr<T>::operator= ( T* p)
ts0->DoSomeThing(); // class #0 doing something. overload T* CPtr<T>::operator ->()
ts1->DoSomeThing(); // class #1 doing something.
ts2->DoSomeThing(); // class #2 doing something.
///////// ts0--->test(0)
///////// ts1--->test(1)
///////// ts2--->test(2)
ts0 = ts1; // class #0 destroyed.
///////// ts0--->test(1)
///////// ts1--->test(1)
///////// ts2--->test(2)
// test(0) is garbage-collected
ts1 = ts2; // overload CPtr<T>& CPtr<T>::operator= ( CPtr<T>& p)
///////// ts0--->test(1)
///////// ts1--->test(2)
///////// ts2--->test(2)
ts0->DoSomeThing(); // class #1 doing something.
ts1->DoSomeThing(); // class #2 doing something.
ts2->DoSomeThing(); // class #2 doing something.
ts1 = ts0;
///////// ts0--->test(1)
///////// ts1--->test(1)
///////// ts2--->test(2)
ts0->DoSomeThing(); //class #1 doing something.
ts1->DoSomeThing(); // class #1 doing something.
ts2->DoSomeThing(); // class #2 doing something.
(*ts0).DoSomeThing(); // class #1 doing something. overload T& CPtr<T>::operator *()
} // class #2 destroyed.class #1 destroyed.