【问题标题】:Subclassing MFC CString, losing implicit conversion when CString passed to format strings (sprintf, CString::FormatString, etc.)子类化 MFC CString,当 CString 传递给格式字符串(sprintf、CString::FormatString 等)时丢失隐式转换
【发布时间】:2013-10-26 03:12:28
【问题描述】:

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

有什么想法吗?

【问题讨论】:

    标签: mfc printf cstring


    【解决方案1】:

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

    相反,您的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());
    

    还请记住:从不提供 virtual 析构函数的类派生是等待发生的资源泄漏。换句话说:不要从CString派生。

    【讨论】:

    • 或者使用函数CString::GetString
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2011-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-18
      • 2011-06-28
      • 2014-03-09
      相关资源
      最近更新 更多