第一个问题,希望我能说对了。
在检查是否可以“强制”缓冲区充当类(带有继承和vptr)时,我尝试了以下代码:
我定义了以下类别:
class a
{
public:
char strBuff[50];
virtual void boo() = 0;
};
class b : public a
{
public:
virtual void boo()
{
printf("%s\n", strBuff);
}
};
并像这样使用它们:
int main()
{
char buffer_allo[100] = "123456789abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz";
b* obj_Ptr = (b*)(buffer_allo);
// Placement new
new (obj_Ptr) b();
// Calling virtual function
obj_Ptr->boo();
return 0;
}
程序的输出为空,例如在\0
缓冲区中,我无法确切知道原因。
我认为这是一个默认初始化\值初始化问题,实际上是将新的放置位置从new (obj_Ptr) b();
更改为
new (obj_Ptr) b;
没有给出空白的输出,而是一个缓冲区,仅覆盖了前8个字符(可能是vptr),
但是后来,我尝试向任一类添加构造函数,并发现向类b添加空构造函数也将阻止使用\0
初始化缓冲区,但是向类a添加构造函数似乎可以没有效果。
为什么会这样?真的是初始化问题吗?如果是这样,为什么要添加一个空的构造函数来解决呢?还是编译器\ c ++标准问题?
答案 0 :(得分:0)
好吧,这是C ++初始化规则的黑暗区域。它们非常复杂,您可以在cppreference中阅读它们。
基本上,当您调用新的展示位置-new (obj_Ptr) b();
(带有一对空括号)时,将进行值初始化。根据标准:
1)如果T是没有默认构造函数或具有用户提供或删除的默认构造函数的类类型,则该对象将被默认初始化;
2)如果T是具有默认构造函数的类类型,该构造函数既不是用户提供也不是删除的(也就是说,它可能是具有隐式定义或默认默认构造函数的类),则该对象为零-initialized ,然后如果它具有非平凡的默认构造函数,则将其默认初始化;
3)如果T是数组类型,则数组的每个元素都将值初始化;
4)否则,该对象将被初始化为零。
由于它是零初始化的,因此调用obj_Ptr->boo();
时将看到此内容。当您定义自己的构造函数时,该对象是默认初始化的,因此您的缓冲区包含垃圾。基本上就是这样。
更详细的说明:value initialization in cppreference
另外,与问题无关,但我想提几件事。
1)正如Slava所指出的,最好直接使用new刊登位置的收益,而无需进行任何强制转换,例如:auto obj_Ptr = new(buffer_allo) b();
2)尽量避免为派生类的方法使用关键字virtual
。最好使用override
,因为它更清晰,当您在派生类中意外创建新函数而不是覆盖基函数时,可能会出错。像这样:void boo() override{...}