1

假设我有这个示例代码:

class A
{
public:
     static void* operator new(size_t sz);

private:
int xA;
float yA;
};

class B : public A
{
private:
int xB;
float yB;
};

void* A::operator new(size_t sz)
{
   void* ptr = (void*)new B();
   return ptr;
}

int main()
{
B* b = (B*) new A();
// Use b ..
delete b;
return 0;
}

这里将按顺序调用构造函数(在 VS2012 中测试):

  • 一个构造函数
  • B 构造函数
  • 一个构造函数

前两个构造函数调用是因为new B()在重载的 operator new 函数中。但是随后将在函数返回的指针上再次调用 A 构造函数,因为重载的运算符 new 应该返回指向空闲内存的指针(不创建对象),因此再次调用构造函数。

b如果我在此示例中使用指针,这是未定义的行为吗?

4

3 回答 3

1

您发布的代码具有无限递归,因为您 A::operator new是从内部调用的A::operator new;类B 继承operator newfrom A

除此之外,您还对编译器撒谎,这会导致未定义的行为。之后new A,您有一个指向类型为 的对象的指针A。您可以合法地将其地址转换为 a B*,但您所能做的B*就是将其转换回A*; 其他任何事情都是未定义的行为。

而且目前还不清楚你想用new Bin实现什么A::operator new。编译器会将任何从 a 返回的operator new内存视为原始内存;在这种情况下,它将在其中构造一个A对象,从那时起,您所拥有的就是一个A对象。任何将其用作B 对象的尝试都是未定义的行为。(当然,如果你真的需要破坏Bcreated in A::operator new,你不能因为你已经覆盖了它。

最后:您不必声明operator newstatic; 暗示是,static在这种情况下不写是惯用的。类似地,将结果分配new B给 avoid*时,转换是惯用的,不使其显式是惯用的。(最好避免 C 风格的强制转换,因为它们隐藏了太多错误。)

于 2013-08-27T13:47:45.683 回答
1

一般来说,operator new()不应该创建一个对象,它应该为一个对象创建空间。您的代码将用一个对象覆盖一个B对象A,然后将其用作一个B对象,是的,这将是“未定义的”(可能在“将对象转换为最初不是创建为的不同类型”下的文档中涵盖)。

这在这种特殊情况下似乎可以工作,但如果 的构造函数B更复杂(例如 中有虚函数B),它将立即无法正常工作。

如果你想为一个对象分配内存,你可以这样做:L

void* A::operator new(size_t sz)
{
   void* ptr = (void*)::new unsigned char[sz];
   return ptr;
}

现在您不会为同一个对象调用两个不同的构造函数!

于 2013-08-27T13:29:32.550 回答
1

的契约operator new只是内存分配,初始化稍后由new 表达式(通过调用构造函数)或如果您直接调用运算符则由程序代码完成。

你想做的事不能做,不能那样做。您可以重新设计以使用将返回指向B对象的指针的工厂成员函数,例如...

于 2013-08-27T13:30:13.003 回答