我的结构是这样的:
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时,我在最后一行遇到了段错误,我不明白为什么。 这是我第一次在这样的结构中使用虚函数,所以我很丢失。任何帮助将不胜感激!
注意:函数调用必须与参数类型的最后一行格式相同,这就是我不使用类或继承的原因。
答案 0 :(得分:2)
您将C语言(嵌入式结构)与C ++概念(虚函数)混合在一起。在C ++中,类和继承消除了对嵌入式结构的需求。 virtual
函数仅影响同一继承层次结构中的类。在您的情况下,A
和B
之间没有任何关系,因此始终会调用A
&#39; s doStuff
。
您的段错误可能是因为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
的实现定义表,它实际上是一个函数指针数组。
答案 1 :(得分:1)
将B *
转换为A *
,然后尝试通过成员函数调用取消引用它是未定义的行为。一种可能性是seg-fault。我不是说这绝对是原因,但这不是一个好的开始。
我不明白你为什么不在这里使用继承!
答案 2 :(得分:0)
对于多态对象,指向vtable的指针存储在对象内
因此,在运行时,实际调用的方法是通过解除引用并跳转到vtable中找到的
在您的情况下,您将B *
投射到A *
由于A
是多态的,因此方法调用将通过vtable确定,但由于所使用的对象实际上是B
所使用的vpointer,实际上是垃圾并且你得到了段错误。