具有嵌入式结构和虚拟函数的段错误

发布于 2024-10-15 02:21:42 字数 799 浏览 9 评论 0原文

我有这样的结构:

struct A
{
     int a;
     virtual void do_stuff(A*a)
     {
          cout << "I'm just a boring A-struct: " << a << endl;
     }
}

struct B
{
     A a_part;
     char * bstr;
     void do_stuff(B*bptr)
     {
          cout << "I'm actually a B-struct! See? ..." << bptr->bstr << endl;
     }
}

B * B_new(int n, char * str)
{
     B * b = (B*) malloc(sizeof(struct B));
     b->a_part.a = n;
     b->bstr = strdup(str);
     return b;
}

现在,当我这样做时:

char * blah = strdup("BLAAARGH");
A * b = (A*) B_new(5, blah);
free(blah);
b->do_stuff(b);

当我调用 do_stuff 时,我在最后一行出现段错误,我不知道为什么。 这是我第一次在这样的结构中使用虚拟函数,所以我很迷失。任何帮助将不胜感激!

注意:函数调用的参数类型必须与最后一行的格式相同,这就是我不使用类或继承的原因。

I have structs like this:

struct A
{
     int a;
     virtual void do_stuff(A*a)
     {
          cout << "I'm just a boring A-struct: " << a << endl;
     }
}

struct B
{
     A a_part;
     char * bstr;
     void do_stuff(B*bptr)
     {
          cout << "I'm actually a B-struct! See? ..." << bptr->bstr << endl;
     }
}

B * B_new(int n, char * str)
{
     B * b = (B*) malloc(sizeof(struct B));
     b->a_part.a = n;
     b->bstr = strdup(str);
     return b;
}

Now, when I do this:

char * blah = strdup("BLAAARGH");
A * b = (A*) B_new(5, blah);
free(blah);
b->do_stuff(b);

I get a segfault on the very last line when I call do_stuff and I have no idea why.
This is my first time working with virtual functions in structs like this so I'm quite lost. Any help would be greatly appreciated!

Note: the function calls MUST be in the same format as the last line in terms of argument type, which is why I'm not using classes or inheritance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

何以笙箫默 2024-10-22 02:21:42

您将 C 习惯用法(嵌入式结构)与 C++ 概念(虚拟函数)混合在一起。在 C++ 中,类和继承消除了对嵌入结构的需求。虚拟函数仅影响同一继承层次结构中的类。在您的情况下, AB 之间没有关系,因此 AdoStuff 始终会接到电话。

您的段错误可能是因为 b 确实是 B,但分配给 A* 引起的。当编译器看到 b->doStuff 时,它会尝试转到 vtable 来查找要调用的 doStuff 版本。但是,B 没有 vtable,因此您的程序会崩溃。

在 C++ 中,没有虚函数且不从任何其他类继承的类的布局与 C 结构体完全相同。

class NormalClass
{
      int a;
      double b;

 public:
      NormalClass(int x, double y);
};

看起来像这样:

+------------------------------------+
| a (4 bytes) | b (8 bytes)          |
+------------------------------------+

但是,具有虚函数的类(或结构)也有一个指向 vtable 的指针,这使得 C++ 版本的多态性成为可能。因此,像这样的类:

 class ClassWithVTable
 {
      int a;
      double b;

   public:
       ClassWithVTable();
       virtual void doSomething();
 };

在内存中的布局如下:

  +-----------------------------------------------------------+
  | vptr (sizeof(void *)) | a (4 bytes) | b (8 bytes)         |
  +-----------------------------------------------------------+

vptr 指向一个名为 vtable 的实现定义表,它本质上是一个函数指针数组。

You're mixing a C idiom (embedded structs) with C++ concepts (virtual functions). In C++, the need for embedded structs is obviated by classes and inheritance. virtual functions only affect classes in the same inheritance hierarchy. In your case, there is no relationship between A and B, so A's doStuff is always going to get called.

Your segfault is probably caused because b is a really a B, but assigned to an A*. When the compiler sees b->doStuff, it tries to go to a vtable to look up which version of doStuff to call. However, B doesn't have a vtable, so your program crashes.

In C++, a class without virtual functions that doesn't inherit from any other classes is laid out exactly like a C struct.

class NormalClass
{
      int a;
      double b;

 public:
      NormalClass(int x, double y);
};

looks like this:

+------------------------------------+
| a (4 bytes) | b (8 bytes)          |
+------------------------------------+

However, a class (or struct) with virtual functions also has a pointer to a vtable, which enables C++'s version of polymorphism. So a class like this:

 class ClassWithVTable
 {
      int a;
      double b;

   public:
       ClassWithVTable();
       virtual void doSomething();
 };

is laid out in memory like this:

  +-----------------------------------------------------------+
  | vptr (sizeof(void *)) | a (4 bytes) | b (8 bytes)         |
  +-----------------------------------------------------------+

and vptr points to an implementation-defined table called the vtable, which is essentially an array of function pointers.

各自安好 2024-10-22 02:21:42

B * 转换为 A *,然后尝试通过成员函数调用取消引用它是未定义的行为。一种可能性是段错误。我并不是说这绝对是原因,但这不是一个好的开始。

我不明白你为什么不在这里使用继承!

Casting a B * to an A * and then attempting to dereference it via a member function call is undefined behaviour. One possibility is a seg-fault. I'm not saying that this is definitely the cause, but it's not a good start.

I don't understand why you're not using inheritance here!

昨迟人 2024-10-22 02:21:42

对于多态对象,指向 vtable 的指针存储在对象内部。
所以在运行时,通过解引用并跳入vtable来找到真正被调用的方法。
在您的情况下,您将 B * 转换为 A *
由于 A 是多态的,因此方法调用将通过 vtable 确定,但由于正在使用的对象实际上是 B,因此使用的 vpointer 实际上是垃圾,并且会出现段错误。

For polymorphic objects, the pointer to the vtable is stored inside the object.
So at runtime, the method to be actually called is found via dereferencing and jumping into the vtable.
In your case you cast B * to A *.
Since A is polymorhic, the method call will be determined via the vtable, but since the object being used is actually B the vpointer used, is actually garbage and you get the segfault.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文