CString是微软程序员的偏爱,用不好也会让你很头疼,又爱又恨啊。
主要实现在三个文件中atlstr.h cstringt.h atlsimpstr.h, atlsimpstr.h负责最基本的设计,cstringt.h则负责一些高级函数的实现,atlstr.h负责最后的封装。
如果在非MFC工程中使用CString的,主要#include <atlstr.h> 就足够了。
看到这段代码,挺有意思^0^
template< typename BaseType = char >
class ChTraitsBase
{
public:
typedef char XCHAR;
typedef LPSTR PXSTR;
typedef LPCSTR PCXSTR;
typedef wchar_t YCHAR;
typedef LPWSTR PYSTR;
typedef LPCWSTR PCYSTR;
};
template<>
class ChTraitsBase< wchar_t >
{
public:
typedef wchar_t XCHAR;
typedef LPWSTR PXSTR;
typedef LPCWSTR PCXSTR;
typedef char YCHAR;
typedef LPSTR PYSTR;
typedef LPCSTR PCYSTR;
};
把传进来的模板参数定义为X,另一种字符则为Y.
CString最基本的血液来自CSimpleStringT,在CSimpleStringT里面我们可以看到CString最核心的设计理念:
---------------------------------------------------------------------------------
| pStringMgr | nDataLength | nAllocLength | nRefs | m_pszData[nAllocLength+1] |
---------------------------------------------------------------------------------
|<-------------CStringData------------------------>|<----------buffer------------>
如图所示,CSimpleStringT的内存前段部分是属性区用CStringData类来管理,后面的buffer则是真正的字符串存储区。
从源码中可以很清晰的看出CSimpleStringT的工作机制,也会理解为什么如果使用GetBuffer()对buffer区的值进行了修改,一定要调用ReleaseBuffer()---要对buffer区的属性进行更新啊。
在struct CStringData中很神奇的一句代码:
void* data() throw()
{
return (this+1);
}
指针加减是有另一套规则的,this+1实际上“1”代表了sizeof(this);同理 m_pchData -1 就到了CStringData内存地址了。
指针相减则是所指向的字符串的长度差。
CString设计的目标是方便、高效,这可以从源码中看出来:
如果一个CString str2是从另一个CString str1赋值过来的,那么不会马上给str2分配内存,而是直接指向str1的内存,此时,str1的nRefs要加1,当str2或者str1的取值发生改变时,才真正的给str2开辟空间。
当nRefs==0时,ReleaseBuffer()才真正的释放这块内存,否则只是nRefs--.
值得注意的是,如果buffer被Lock了(可以被Lock的前提是未被share),nRefs=-1.
看,CSimpleStringT把关键字PCXSTR都定义成operator了:
operator PCXSTR() const throw()
{
return( m_pszData );
}
另外,封装中用到了很多**TraitsOS **TraitsCRT **TraitsATL
看看里面的代码,其实就是定义了一些非CString方法的一些辅助实现方法。
参考:
http://blog.kingsamchen.com/archives/550
http://blog.csdn.net/chenjin824/article/details/1214874