可能重复:
C++: why isnew
needed?
为什么我不能使用malloc为我的对象分配空间,因为它们是包含虚函数的类的子节点?这真令人沮丧。有充分的理由吗?
以下程序说明了问题。它在第27行进行了段错误,我称之为aa-> f()
#include <iostream>
#include <cstdlib>
class A
{
public:
virtual int f() {return 1;}
};
class B
{
public:
int f() {return 1;}
};
class Aa : public A {};
class Bb : public B {};
int main()
{
Aa* aa = (Aa*)malloc(sizeof(Aa));
Aa* aan = (Aa*)new Aa();
Bb* bb = (Bb*)malloc(sizeof(Bb));
std::cout << bb->f() << std::endl;
std::cout << aan->f() << std::endl;
std::cout << aa->f() << std::endl;
return 0;
}
版本信息:g ++(Ubuntu / Linaro 4.4.4-14ubuntu5)4.4.5
答案 0 :(得分:6)
实现虚函数的一种常用方法是在与对象的负偏移处指向“虚拟表”或vtable。需要此表来确定要调用的虚函数。这就是为什么只有malloc'ing空间不起作用。
答案 1 :(得分:6)
malloc
仅分配内存,但不创建对象。那么,行
Aa* aa = (Aa*)malloc(sizeof(Aa));
分配一个足够大的内存区域来容纳A
,但包含垃圾。正如其他人所指出的那样,这也意味着将不会设置指向vtable
的指针(我从@DavidRodríguez对另一个答案的评论中得到了这个指针),这是调度虚拟函数所必需的。由于B
不包含虚函数,因此不会出现此类问题。但是,如果B
包含任何需要初始化的数据成员,那么B
也会发生这种情况,例如:
class B
{
public:
B() : foo(new int()) {}
int f() {return *foo;}
private:
int * foo;
};
该行
Aa* aan = (Aa*)new Aa();
没有演员阵容可以做到:
Aa* aan = new Aa();
答案 2 :(得分:6)
原因是malloc
对C ++构造函数一无所知,因此不会调用它们。您可以使用placement new
自行调用构造函数:
int main()
{
Aa* aa = (Aa*)malloc(sizeof(Aa));
new(aa)Aa;
Aa* aan = (Aa*)new Aa();
Bb* bb = (Bb*)malloc(sizeof(Bb));
new(bb)Bb;
std::cout << bb->f() << std::endl;
std::cout << aan->f() << std::endl;
std::cout << aa->f() << std::endl;
aa->~Aa();
free(aa);
delete aan;
bb->~Bb();
free(bb);
return 0;
}
请注意,您必须在释放此类内存之前手动调用析构函数。
答案 3 :(得分:2)
不要使用malloc,使用new - malloc不会调用构造函数。
执行A * a = new A();
时,编译器将分配内存,为A 设置vtable指针并调用构造函数。当您调用虚函数时,vtable用于实际查找函数。
执行A * a = (A *) malloc(...);
时,编译器将分配内存,其中包含随机数据。当你调用虚函数时,它会查看(垃圾)vtable并调用一些随机位置。
具有虚函数的类在内部看起来像这样:
struct Foo {
void * vtable;
int aClassMemberVar;
};
调用虚函数会查看“隐藏”vtable指针,该指针指向类 vtable,这是指向函数的指针的链接列表。所以必须初始化这个vtable指针,而malloc不会这样做。
答案 4 :(得分:1)
当然是因为虚拟功能表没有正确创建?
答案 5 :(得分:0)
malloc
不会调用类的构造函数,因此您的对象未正确初始化,因此它会出错。使用new
时使用C ++分配内存。顺便说一句,没有必要转换从new
返回的指针。
答案 6 :(得分:0)
很好的理由称为虚拟表。具有虚方法的类型的对象具有指向要调用的实际虚拟方法的地址的指针表。这些称为虚拟表或v表。