我看到了一些像这样的代码:
class BaseClass
{
public:
BaseClass(int param);
};
class Derived: public BaseClass
{
};
BaseClass::BaseClass(int param)
{
new (this) Derived;
}
代码试图做什么?我认为它会创建一个派生类对象。但是,背后的逻辑是什么?我想当我们调用new BaseClass()时,它只会根据基类大小分配内存。但是,为什么我们仍然可以将此指针传递给新的位置来构造Derived类对象?
编辑: 谢谢回复。在进一步检查时,代码确实为基类覆盖operator new以分配足以保存派生类对象的内存并避免递归调用它,在派生类构造函数中,它调用另一个基类构造函数。
基本上我认为它正在尝试创建像工厂一样创建对象的东西取决于参数。根据答复,这样做似乎不是一个好习惯。
答案 0 :(得分:13)
这是大约六个bajillion原因的可怕的未定义行为。不要永远这样做。
答案 1 :(得分:6)
这会在DerivedClass
指向的内存上调用this
的构造函数。因此,new
运算符不会分配任何内容,它只是调用构造函数来初始化已经分配的内存中的对象。
但是,在这种特殊情况下,结果最好是非常奇怪。您实际上是使用派生类的构造函数初始化基类的对象。结果是你仍然拥有基类的对象,但是具有派生类的状态,或者至少假装具有这样的状态。根据派生类是否引入了构造函数引用的一些新字段,这甚至可能导致内存访问违规......
所以,简短的建议:不要这样做。一般情况下,除非你真的知道自己在做什么,否则不要使用 placement new 。
答案 2 :(得分:2)
该代码中存在许多错误。对于初学者来说,要选择一些简单的构造函数,构造函数不应该在类声明中进行限定。
接下来就是它正在做的事情:看起来它正在为Derived
分配的内存中创建一个Base
类型的对象。
Derived
可能需要比Base
更多的内存,并且无法保证内存可用。Base
的构造函数正在尝试创建Derived
,而后者将尝试调用Base
的构造函数,这将尝试创建Derived
... Base
构造函数,并将被调用的Derived
构造函数调度到该非循环版本),并且Derived
适合内存占用Base
的{{1}}已经初始化的任何成员将重新初始化调用未定义的行为。例如,如果Base
包含在内部分配和管理内存的属性,则其构造函数将被调用两次泄漏第一次调用中获取的资源。构造和破坏的物体数量分别不匹配。答案 3 :(得分:1)
这是未定义的行为,它可能递归地调用基类构造函数,你将获得无限递归。
答案 4 :(得分:0)
它试图声明DerivedClass类型的成员对象并将其指针强制转换为Baselass类型。 虽然它甚至没有编译。
答案 5 :(得分:0)
我认为这背后没有逻辑。顺便说一句,在构建派生实例时,C ++中的对象首先被初始化为一个基础(即首先执行base的构造函数)。因此,我会说这段代码将永远地递归调用(直到堆栈空间耗尽,即)。
答案 6 :(得分:0)
您的代码无法编译。
没有为Derived
定义构造函数,并且编译器无法生成默认构造函数,因为Base
只有一个需要参数的构造函数。