14

我对 的感觉很复杂static_cast,因为它是可用的最安全的 C++ 转换,但同时允许安全和不安全的转换,所以你必须知道上下文来说明它是否真的安全或可能导致 UB(例如,在转换时到一个子类)。

那么为什么没有更安全的显式转换呢?这是一个示例,它可能有用。在 COM 中,它们必须将接口指针返回为void** ppv,因此“必须”显式转换

*ppv = (IInterface*) this;

然后建议将其替换为更安全的 C++ 演员表

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

static_cast但是,即使在这里也有意义吗?this是一个派生自 的类IInterface,因此可以简单地写

IInterface* p = this; // implicit conversion to base, safe for sure
*ppv = p;

或使用像

template<class T, class U>
T implicit_cast(U p) { return p; }

*ppv = implicit_cast<IInterface*>(this);

那么,static_cast有时会被误用并且可以(应该?)在某些情况下被这个取代implicit_cast,还是我错过了什么?

编辑:我知道在 COM 中需要强制转换,但不一定是static_cast,隐式强制转换就足够了。

4

1 回答 1

5

在这种特殊情况下,我相信总是知道铸件会向上,因此static_cast应该是完全安全的。

看起来使用你的implicit_cast可能会更安全,并且允许你显式地选择你想要隐式转换到的基类(这显然是 COM 所必需的)。

我用 g++ 做了一个快速测试,implicit_cast确实按预期返回了不同基类的不同地址。

但是请注意,关于您的第一句话,我认为这dynamic_cast实际上比它更安全,static_cast因为如果无法完成演员表,它将返回 null 或 throw 。相反,static_cast将返回一个看起来有效的指针,并让您继续运行,直到您的程序在将来的某个时间爆炸,与原始的错误转换无关。

测试程序:

#include <iostream>

class B1
{
public:
    virtual ~B1() {}
};

class B2
{
public:
    virtual ~B2() {}
};

class Foo : public B1, public B2
{
};

template<class T, class U>
T implicit_cast(U p) { return p; }

int main()
{
    Foo* f = new Foo;
    void **ppv = new void*;

    *ppv = implicit_cast<B1*>(f);
    std::cout << *ppv << std::endl;;
    *ppv = implicit_cast<B2*>(f);
    std::cout << *ppv << std::endl;;

    return 0;
}
于 2011-02-10T14:42:59.407 回答