With a string you have some memory where it is actually stored and you have a pointer to this memory which references the string. If you want to create a copy of the string you must copy the memory which requires allocating new memory for it.
There are also some errors and possible optimisations in your code.
For example you should delete the old memory when allocating a new block and when the object is destroyed:
CString CString::operator =(const CString &q)
{
cout << "operator =" << endl;
if (this != &q)
{
delete[] cstr;
if (q.cstr)
{
cstr = new char[strlen(q.cstr) + 1];
strcpy(cstr, q.cstr);
}
else
cstr = 0;
}
return *this;
}
CString::~CString()
{
delete[] cstr;
}
Once you have implemented the assignment operator, it can be used by other functions:
CString::CString(const CString& q)
{
cout << " copy constructor" << endl;
*this = q;
}
Knowing this it might be better to have a
CString::CString(const char *s)
assignment operator instead because that can be used for multiple copy constructors.