我正在对MFC类CString进行子类化(该类没有任何问题,但相信我,我需要为特定的实现执行此操作)。 我已经成功地自定义了一些行为,但我注意到我丢失了隐式 (LPCTSTR) 运算符,该运算符似乎在将 CString 传递到格式字符串时发生。 无论是CString::Format还是prinf/sprintf,这种魔术都会发生。 例如:
CString Str = _T("Really cool string");
TCHAR szBuffer[32];
_stprintf(szBuffer, _T("Here it is: %s"), Str);
我还没有弄清楚这种魔力是如何与标准 CString 一起工作的,因为 CString::FormatString 只是将变量参数列表传递给 _vswprintf 和 _swprintf。 但是,无论它做什么,在我的派生类中都缺少。
运算符 (LPCTSTR) 按预期继承,并在显式调用时工作。
有什么想法吗?
您的假设是错误的:当CString
对象传递给printf
样式函数时,没有隐式转换为LPCTSTR
。编译器无法知道这就是你想要的 - 它不会解析格式字符串来推断类型信息。
相反,您的CString
对象将按原样传递给printf
。这里的神奇之处在于,CString
作者预测了关于何时以及如何调用隐式强制转换运算符的错误假设,并CString
建模以与 C 字符串兼容。为此,CString
包含一个LPTSTR
指针,不包含向量表。现在,如果将CString
对象传递给 printf
样式的函数,则只有此指针将作为参数结束,并且一切似乎都正常工作。请注意,看似有效是未定义行为的有效形式。这是未定义的行为。
如果您想知道CString
将剩余信息(当前大小、容量等)存储在何处,它驻留在字符缓冲区之前的内存中。这样,所有信息都可以通过单个指针获得:
CStringData* GetData() const throw() {
return( reinterpret_cast< CStringData* >( m_pszData )-1 );
}
现在解决你的真正问题:不要依赖未定义的行为,在必要时使用显式强制转换,没有人会受到伤害:
_stprintf(szBuffer, _T("Here it is: %s"), static_cast<LPCTSTR>(Str));
作为演员表的替代品,您可以调用CString::GetString()
:
_stprintf(szBuffer, _T("Here it is: %s"), Str.GetString());
另请记住:从不提供虚拟析构函数的类派生是等待发生的资源泄漏。换句话说:不要从CString
派生。
从类派生时,并非所有运算符都是继承的。 谷歌C++中的运算符继承主题。 在派生类中,可能需要实现运算符并简单地转发到基类。