我可以在CString
中使用CString::Format
,如下所示:
CString text = _T("text");
CString format;
format.Format(_T("%s"), text);
在MFC源文件和MFC书籍中可以看到相同的方法。例如:
//From MFC file:
//C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\
// afxeditbrowsectrl.cpp
BOOL CMFCEditBrowseCtrl::OnIllegalFileName(CString& strFileName)
{
CString strError;
CString strMessage;
...
strMessage.Format(_T("%Ts\r\n%Ts"), strFileName, strError);
//I don't know what is the `T` in `"%Ts"` !
...
}
然而,其他MFC源文件使用LPCTSTR
强制转换。例如:
format.Format(_T("%s"), (LPCTSTR)text);
强制转型?
答案 0 :(得分:4)
来自CStringT
课程模板的文档:
您可以自由地将
CStringT
个对象替换为PCXSTR
函数参数。
每当函数参数需要一个常量的C风格字符串时,您可以传递一个CStringT
对象,该对象通过调用operator PCXSTR()进行隐式转换。
另一方面,具有variadic arguments的函数采用无类型的参数列表。在这种情况下,传递一个CStringT
对象,其中PCXSTR
(语义上)是预期的,这是不安全的。编译器无法知道它应该发出代码来执行隐式转换。您有责任通过调用operator PCXSTR()
或调用GetString()类成员来自行执行转换。
就记录的合同而言。要理解为什么通过可变参数列表传递CStringT
仍然(技术上)安全,有助于查看实现 1 :
CSimpleStringT类模板是所有支持的字符串类的基础。它包含PCXSTR
类型的单个(私有)数据成员,没有虚函数,使其成为standard layout类型。因此二进制表示与其唯一成员的表示相同,指向零终止字符数组的指针。
与此Q& A的讨论无关,但为了完整起见,以下是CSimpleStringT
如何跟踪附加数据(如字符串长度或引用计数)的简要说明。唯一的数据成员m_pszData
指向CStringData类型的结构,它由一个常量大小的初始序列组成,存储簿记信息,紧接着是一个长度为nAllocLength + 1
的字符数组。 m_pszData
指向此数组,并通过指针算法检索其他数据,由私有GetData()
成员实现:
CStringData* GetData() const throw()
{
return( reinterpret_cast< CStringData* >( m_pszData )-1 );
}
类布局总结如下图:
+------------------------+
| CStringData |
+========================+
| pStringMgr |
+----------------+ | nDataLength |
| CSimpleStringT | | nAllocLength |
+================+ | nRefs |
| m_pszData | ---> | data[0] |
+----------------+ | data[1] |
. ... .
| data[nAllocLength - 1] |
| data[nAllocLength] |
+------------------------+
1 这是基于Visual Studio 2017附带的实现,理论上可以在不事先通知的情况下进行更改。
答案 1 :(得分:2)
如果您不使用演员表,则按值传递CString对象。这恰好因为CString的实现方式而有效,并且无法保证CString实现永远不会改变。