【问题标题】:What harsh examples are there showing C-style casts are bad?有哪些苛刻的例子表明 C 风格的演员表不好?
【发布时间】:2011-06-20 13:38:48
【问题描述】:

最近我发现了一个很好的例子来说明为什么 C 风格的强制转换不好。我们从实现多个 COM 接口的以下类开始(为了简洁起见,我有两个,但在现实生活中可能有十个):

class CMyClassInitial : public IInterface1, public IInterface2 {
    //declarations omitted
};

HRESULT CMyClassInitial::QueryInterface(REFIID iid, void** ppv)
{
    if( ppv == 0 ) {
       return E_POINTER;
    }
    *ppv = 0;
    if( iid == __uuidof(IUnknown) || iid == __uuidof(IInterface1) ) {
       *ppv = (IInterface1*)this;
    } else if( iid == __uuidof(IInterface2) ) {
       *ppv = (IInterface2*)this;
    } else {
       return E_NOINTERFACE;
    }
    AddRef();
    return S_OK;
}

上面的实现对adjusting pointers to account for multiple inheritance 使用了C-casts。它们甚至可以作为 static_casts 工作 - this 指针值将被适当调整。

现在我们将相同的QueryInterface() 实现复制粘贴(或者我应该说重用代码?)到其他一些非常相似的类。

class CMyClassModified : public IInterface1 {
    //declarations omitted
};

并保持实现不变。新类不再继承自 IInterface2,而是

} else if( iid == __uuidof(IInterface2) ) {
*ppv = (IInterface2*)this;
}

将编译得很好,C 风格的转换将充当reinterpret_cast - this 指针值将被复制而不变。 调用者将获得一个指向实际上并未实现 IInterface2 的对象的指针 - 直接导致未定义行为。在庞大的数据库中以及当有很多(不是我的示例中的两个)接口时,很难发现此类问题。

如果使用了static_cast,这将不会发生 - 编译器会在尝试编译时发出错误

*ppv = static_cast<IInterface2*>(this);

IMO 这是一个足够严酷的例子,说明使用 C 风格的强制转换会导致严重的问题。

还有哪些例子?

【问题讨论】:

  • 一个很好的陷阱,但我不完全确定这是否适合 SO。似乎很有讨论性。充其量它是一个社区维基。
  • @tenpn:我看不出这里可以讨论什么——只是一个用 C++ 射击自己腿的例子。
  • @sharptooth 但这不是问题,不是吗?
  • @tenpn:嗯...我问还有什么其他的例子。这不是问题吗?
  • 这也可以作为一个例子,说明为什么复制粘贴代码(尤其是没有彻底阅读它)通常是一个坏主意。

标签: c++ casting


【解决方案1】:

This FAQ item 总结了 C-cast 不好的原因。

任何 C 风格的转换都可能成为炸弹,因为它们通过使编译器静音来隐藏转换警告和错误。

既然你想要一个例子,那就是:

int main()
{
    float a = 0.123;
    double *b = ( double* ) &a;
    *b = 0.123;
}

【讨论】:

  • 很好的常见问题解答项目,但它是关于一般的演员表,而不是具体的 C 演员表。
  • @sharptooth 我猜你是对的。然而,每一个像样的 c++ 编码风格指南都会告诉你不要使用 c 风格的强制转换。
【解决方案2】:

一个非常简单的例子:

class ClassB;//only forward declaration, no real declaration included

Class A * a;
Class B * b;
a = (ClassA *)b;

如果只有 ClassB 的前向声明,则转换总是会默默成功。它不关心 ClassB 是否派生自 ClassA。 而且当ClassB不仅仅派生自ClassA时也会出错:

class ClassB:public SomeOtherClass, public ClassA {};

【讨论】:

    猜你喜欢
    • 2019-03-25
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 2021-01-22
    相关资源
    最近更新 更多