具有嵌入式结构和虚拟函数的段错误
我有这样的结构:
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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您将 C 习惯用法(嵌入式结构)与 C++ 概念(虚拟函数)混合在一起。在 C++ 中,类和继承消除了对嵌入结构的需求。虚拟函数仅影响同一继承层次结构中的类。在您的情况下,
A
和B
之间没有关系,因此A
的doStuff
始终会接到电话。您的段错误可能是因为
b
确实是B
,但分配给A*
引起的。当编译器看到b->doStuff
时,它会尝试转到 vtable 来查找要调用的doStuff
版本。但是,B
没有 vtable,因此您的程序会崩溃。在 C++ 中,没有虚函数且不从任何其他类继承的类的布局与 C 结构体完全相同。
看起来像这样:
但是,具有虚函数的类(或结构)也有一个指向 vtable 的指针,这使得 C++ 版本的多态性成为可能。因此,像这样的类:
在内存中的布局如下:
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 betweenA
andB
, soA
'sdoStuff
is always going to get called.Your segfault is probably caused because
b
is a really aB
, but assigned to anA*
. When the compiler seesb->doStuff
, it tries to go to a vtable to look up which version ofdoStuff
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.
looks like this:
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:
is laid out in memory like this:
and
vptr
points to an implementation-defined table called thevtable
, which is essentially an array of function pointers.将
B *
转换为A *
,然后尝试通过成员函数调用取消引用它是未定义的行为。一种可能性是段错误。我并不是说这绝对是原因,但这不是一个好的开始。我不明白你为什么不在这里使用继承!
Casting a
B *
to anA *
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!
对于多态对象,指向 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 *
toA *
.Since
A
is polymorhic, the method call will be determined via the vtable, but since the object being used is actuallyB
the vpointer used, is actually garbage and you get the segfault.