我可以在 CString::Format
中使用 CString
吗,如下所示:
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);
Actor 是强制性的吗?
最佳答案
来自 CStringT
类模板的文档:
You can freely substitute
CStringT
objects forPCXSTR
function arguments.
每当函数参数需要一个常量 C 风格字符串时,您可以传递一个 CStringT
对象,该对象通过调用 operator PCXSTR() 隐式转换。 .
带有 variadic arguments 的函数,另一方面,采用未类型化的参数列表。在这种情况下,传递 CStringT
对象(在语义上)预期为 PCXSTR
的地方是不安全的。编译器无法知道它应该发出代码来执行隐式转换。您负责自己执行转换,方法是调用 operator PCXSTR()
,或调用 GetString()类(class)成员。
就记录在案的契约(Contract)而言。要理解为什么通过可变参数列表传递 CStringT
仍然(技术上)安全,查看实现1 会有所帮助:
CSimpleStringT类模板是所有支持的字符串类的基础。它包含类型为 PCXSTR
的单个(私有(private))数据成员,并且没有虚函数,使其成为 standard layout。类型。因此,二进制表示与其唯一成员的二进制表示相同,即指向以零结尾的字符数组的指针。
与本问答的讨论无关,但为了完整起见,这里简要解释一下 CSimpleStringT
如何跟踪附加数据(如字符串长度或引用计数)。唯一的数据成员m_pszData
指向类型为CStringData 的结构。 ,它由一个恒定大小的初始序列组成,用于存储簿记信息,紧接着是一个长度为 nAllocLength + 1
的字符数组。 m_pszData
指向这个数组,附加数据通过指针算法检索,由私有(private) 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 附带的实现,理论上可以更改,恕不另行通知。
关于c++ - 在 CString::Format 中使用 CString 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48245284/