子类化MFC CString,当CString传递给格式字符串(sprintf,CString :: FormatString等)时丢失隐式转换

时间:2013-10-17 14:45:52

标签: mfc printf cstring

我正在继承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)按预期继承,并在显式调用时工作。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您的假设是错误的:当LPCTSTR对象传递给CString样式函数时,没有隐式转换为printf。编译器无法知道这是你想要的 - 它不会解析格式字符串来推断类型信息。

相反,您的CString对象会按原样传递给printf 。这里的神奇之处在于CString作者预测了关于何时以及如何调用隐式强制转换操作符以及如何将CString建模为与C字符串兼容的错误假设。为此,CString包含一个LPTSTR指针,没有v-table。现在,如果将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

答案 1 :(得分:0)

从类派生时,并非所有运算符都是继承的。 Google是C ++中运算符继承的主题。在派生类中,您可能需要实现运算符并简单地转发到基类。