c++类型转换,用于C风格的向下转换

C++ casting for C-style downcasting

本文关键字:转换 风格 类型转换 用于 c++      更新时间:2023-10-16

当使用使用C风格继承的C API时,(利用C结构的标准布局),例如GLib,我们通常使用C风格的强制转换来向下转换:

struct base_object
{
    int x;
    int y;
    int z;
};
struct derived_object
{
    base_object base;
    int foo;
    int bar;
};
void func(base_object* b)
{
    derived_object* d = (derived_object*) b; /* Downcast */
}


但是,如果我们正在编写新的c++代码,使用像这样的C- api,我们应该继续使用C风格的强制转换,还是应该使用c++强制转换?如果是后者,我们应该使用哪种类型的c++强制转换来模拟C向下强制转换?

起初,我认为reinterpret_cast是合适的:

derived_object* d = reinterpret_cast<derived_object*>(b);

然而,我总是对reinterpret_cast保持警惕,因为c++标准对将要发生的事情几乎没有保证。static_castvoid*可能更安全:

derived_object* d = static_cast<derived_object*>(static_cast<void*>(b))

当然,这确实很麻烦,使我认为在这种情况下使用c风格的强制转换更好。

那么这里的最佳实践是什么呢?

如果您查看c++规范中关于C风格强制转换的规范,您会发现强制转换符号是根据其他类型转换操作符(dynamic_cast, static_cast, reinterpret_cast, const_cast)定义的,在本例中使用reinterpret_cast

此外,reinterpret_cast提供了比您链接到的答案所指示的更多的保证。你关心的是:

§9.2/20:使用reinterpret_cast适当转换后,指向标准布局结构对象的指针指向其初始成员(或者,如果该成员是位域,则指向其所在的单元),反之亦然。

如果你想使用强制转换表示法,我认为明确使用c++类型转换操作符是最好的。但是,与其在代码中乱扔强制类型转换,不如为每个转换编写一个函数(使用reinterpret_cast实现),然后使用它。

derived_object *downcast_to_derived(base_object *b) {
    return reinterpret_cast<derived_object*>(b);
}

然而,我总是对reinterpret_cast保持警惕,因为c++标准对将要发生的事情几乎没有保证。

c++风格的强制转换并不比C风格的强制转换更安全,因为C风格的强制转换是根据c++风格的强制转换定义的。

5.4.4 执行的转换

- a const_cast (5.2.11),

-一个static_cast (5.2.9),

—一个static_cast后跟一个const_cast,

-一个reinterpret_cast(5.2.10),或

—reinterpret_cast后跟const_cast,

可以使用显式类型转换的强制转换符号来执行。

[…]

如果一个转换可以用以上列出的一种以上的方式来解释,那么这种解释出现在列表的第一个被使用,即使由该解释产生的强制转换是错误的。

可悲的答案是,你无法避免代码中的强制类型转换,因为编译器对类之间的关系知之甚少。无论如何,您可能想要重构它(强制类型转换、类或使用它们的代码)。

底线是:

如果可以,使用适当的继承。

如果不能,使用reinterpret_cast

使用如下C- api的新c++代码

不要用C风格编写新的c++代码,它不能利用c++语言的特性,而且它还迫使包装器的用户使用相同的"C"风格。相反,创建一个合适的c++类来包装C API接口细节,并将它们隐藏在c++类后面。

应该继续使用c风格的强制类型转换吗

没有

或者我们应该使用c++强制类型转换

是的,但只有当你必须的时候。

使用c++继承和虚访问器函数(可能)。请说明你打算如何在函数中使用派生对象,这可能会为你提供一个更好的答案。

如果func期望使用派生对象的方法,那么它应该接收派生对象。如果它期望使用base_object的方法,但由于指针指向派生对象而改变了方法,则虚函数是实现此目的的c++方法。

同时,你想传递一个引用给func,而不是一个指针。

dynamic_cast,需要满足某些条件:

http://www.cplusplus.com/doc/tutorial/typecasting/

如果你只是转换结构体ptrs到结构体ptrs,你知道你想要什么,那么static_cast,或reinterpret_cast可能是最好的?

但是,如果您真的对编写c++代码感兴趣,那么强制类型转换应该是您最后的手段,因为有更好的模式。我考虑强制转换的两种常见情况是:

  • 您正在与一些事件传递机制接口,该机制将泛型基类传递给事件处理程序。

  • 你有一个对象的容器。容器要求它包含同质类型(即每个元素都包含相同的"东西"),但你想在容器中存储不同的类型。

我认为dynamic_cast正是你想要的。