c++ - 虚函数并强制转换为 void 并返回

标签 c++ virtual void reinterpret-cast static-cast

目前我正在使用遗留的 c++ 代码库。在此代码库中,指向对象的指针被转换为空指针,然后存储在 c 库中。 考虑以下代码:

class interface {
public:
  virtual void foo() {
    std::cout << "Interface" << std::endl;}
  virtual ~interface(){};
};

class debug_interface: public interface {
public:
  virtual void foo() {
   std::cout << "Debug Interface" << std::endl;}
};

对象interfacedebug_interface 分配在堆上,地址存储到空指针。在某些时候,指针被检索,然后被转换回基类 interface。然后调用虚函数调用。见

int main(int argc, char *argv[]){

    void *handle = reinterpret_cast<void*>(new interface());
    void *debug_handle = reinterpret_cast<void*>(new debug_interface());

   //void *handle = new interface();
   //void *debug_handle = new debug_interface();

   interface *foo1 = reinterpret_cast<interface*>(handle);
   interface *foo2 = reinterpret_cast<interface*>(debug_handle);

   //interface *foo1 = static_cast<interface*>(handle);
   //interface *foo2 = static_cast<interface*>(debug_handle);

   foo1->foo();
   foo2->foo();

   return 0;
}

首先我不明白,为什么要用reinterpret_cast。据我所知,指向对象的指针可以隐式转换为 void*。此外,要使此转换显式化,static_cast 就足够了,对吗? 但更重要的问题是:将指针 debug_handle 转换为 interface*(而不是 debug_interface*)并调用虚拟调用真的省事了吗?根据 c++ 标准,(5.2.10) 这是未定义的行为:

A pointer to an object can be explicitly converted to a pointer to a different object type.69 When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast(static_cast(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

handlefoo1 的转换应该没问题,但我可以再次使用 static_cast 吗?

编辑 我的示例源代码是错误的。 debug_interface 是接口(interface)的派生类。

最佳答案

免责声明: 第一部分是在两个接口(interface)没有继承关系时编写的。

未定义的行为实际上发生在这里:

   foo2->foo();

在这里,您在指向实现此 API 的对象的指针上使用 interface API。 interfacedebug_interface 碰巧实现了 foo() 成员作为它们的第一个方法这一事实并没有改变任何东西:这些类是不相关的通过继承,所以它们不兼容。

您引用的摘录涉及允许转换 本身的情况。在你的情况下,我的理解是你实际上可以将指向 debug_interface 的指针转换为指向 interface 的指针:然而,你现在可以用指向的指针做的唯一安全的事情interface 是将其转换回 debug_interface 指针:使用它访问 interface 成员是不安全的。


编辑:如果debug_interface 公开派生自interface,这是一个不同的问题。

在这种情况下,从 debug_interface* 转换为 interface* 是完全安全的:derived-to-base 转换可以甚至被编译器隐式应用。 然而为了安全起见,必须通过以下任一方式直接完成此转换:

  • 一个static_cast
  • dynamic_cast(这会引入运行时检查,对于向上转换来说太过分了)。

通过两个 reinterpret_cast 完成它是一个未定义的行为:它可能适用于单继承(在某些编译器上),但它绝对不受标准保证。
通过两个 static_cast 来完成它也将是一个未定义的行为。该标准保证(强调我的):

A value of type pointer to object converted to “pointer to cv void” and back to the original pointer type will have its original value.

在您的示例中,您并没有转换回原始指针,而是转换回另一种指针类型:标准并未就您将获得的值向您提供任何保证。

可能的解决方案

知道:

  1. 直接从debug_interface转换成interface是安全的
  2. 从指向对象类型的指针转​​换为 void * 然后返回指向同一对象类型的指针是安全的。

您可以将其组装起来以获得标准的有保证的解决方案:

// Safe, see point #1.
// The new expression returns a debug_interface* and static_cast applies a derived-to-base conversion.
interface *debug_handle_interim = static_cast<interface*>(new debug_interface());

// Convert a interface* to void* then back to interface*, see #2
void *type_erased = static_cast<void*>(debug_handle_interim);
interface *debug_handle_back = static_cast<interface*>(type_erased);

关于c++ - 虚函数并强制转换为 void 并返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32134719/

相关文章:

C++ 模板 : Calling member function of derived template class from base class

c++ - Virtual destructor和Vtable之间有什么关系吗

C char函数(void)和void函数(void)的区别

javascript - 如何捕获Javascript :void(0)

c++ - 从源代码本身获取输入 C++

c++ - SDL2 操纵杆事件未触发

c++ - 我无法使用 C++ 进入目录

c++ - 具有虚函数的未解析外部符号

linux-kernel - 在现代 Linux(2.6.30+ 内核)系统上可以创建(和安装)多少个循环设备?

java - "' 无效 ' type not allowed here "错误消息