2

我有一个派生自 C 结构的类。该类没有做任何特殊的事情,除了在构造函数中进行初始化、在析构函数中取消初始化函数以及调用 C 函数的一些其他方法。基本上,它是一个普通的包装器。使用 GCC,它抱怨我的析构函数不是虚拟的,所以我做到了。现在我遇到了段错误。

/* C header file */
struct A
{
  /* ... */
}

// My C++ code
class B : public A
{
public:
  B() { /* ... init ... */ }
  virtual ~B() { /* ... deinit ... */ }

  void do()
  {
    someCFunction(static_cast<A *>(this));
  }
};

我总是假设static_cast它将返回正确的指向基类的指针,修剪掉虚拟表指针。所以情况可能并非如此,因为我在 C 函数中遇到了段错误。

通过删除virtual关键字,代码可以正常工作,除了我收到 gcc 警告。最好的解决方法是什么?随意启发我:)。

4

3 回答 3

4

显式和隐式转换A*都是安全的。既不需要显式强制转换,也不会在任何地方引入 vtable 或类似的东西。如果不是这种情况,该语言将根本无法使用。

我总是假设 static_cast 会返回正确的指向基类的指针,修剪掉虚拟表指针。

是绝对正确的。

仅当在具有类型的地方调用析构函数或手动调用析构函数virtual时才需要析构函数。它必须是虚拟的 ' 析构函数,但事实并非如此。delete ptr;ptrA*A

无论您的代码有什么问题,它都与显示的代码无关。您需要大大扩展您的样本。

于 2012-05-10T19:36:43.787 回答
1

基类的析构函数应该是虚拟的。否则,您可能会遇到未定义的行为。这只是一个猜测,因为代码不足以说明实际原因。

尝试制作Avirtual 的析构函数,看看它是否崩溃。

请注意,aclass和 astruct是相同的东西,除了默认访问级别,因此一个是类而另一个是结构的事实与它无关。

编辑:如果A是 C 结构,使用组合而不是继承 - 即在A内部有一个成员B而不是扩展它。没有必要推导,因为多态性是不可能的。

于 2012-05-10T19:18:39.253 回答
1

这不是如何static_cast工作的。指向对象的指针仍然是相同的指针,只是类型不同。在这种情况下,您要将指向派生类型 ( B) 的指针转换为指向基类型 ( A) 的指针。

我的猜测是转换指针实际上并没有改变指针值,即它仍然指向相同的内存地址,即使它被转换为A*指针类型。请记住,structandclass是 C++ 中的同义词。

正如@Luchian 所说,如果您混合使用 C 和 C++,最好将普通的旧 C 结构(及其指针)保留为普通的旧 C 结构,并使用类型组合而不是继承。否则,您将在幕后混合不同的指针实现。不能保证 C 结构和 C++ 类的内部排列是相同的。

更新

您应该用规范包围 C 结构声明extern "C",以便 C++ 编译器知道该结构是纯 C 结构:

extern "C"
{
    struct A
    {
        ...
    };
}

或者:

extern "C"
{
#include "c_header.h"
}
于 2012-05-10T19:26:48.137 回答