通过在类中重载operator new返回不同的类指针

时间:2013-08-27 13:19:02

标签: c++ pointers constructor new-operator

假设我有这个示例代码:

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函数中的new B()。 但是然后将在函数返回的指针上再次调用A构造函数,因为重载的operator new应该返回一个指向空闲内存的指针(不创建对象),因此再次调用构造函数。

如果我在这个例子中使用指针b,这个未定义的行为是什么?

3 个答案:

答案 0 :(得分: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;
}

现在你没有为同一个对象调用两个不同的构造函数!

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

你发布的代码有无限的递归,因为你打电话 来自A::operator new内的A::operator new;班级Boperator new继承A

除此之外,你撒谎到编译器,导致未定义 行为。在new A之后,你有一个指向一个对象的指针 类型为A。您可以合法地将其地址转换为B*,但是 您可以使用B*将其转换回A*; 其他任何事都是未定义的行为。

目前尚不清楚您在new B中使用A::operator new尝试实现的目标。编译器会考虑任何内存 从operator new作为原始记忆返回;在这种情况下,它 将在其中构建一个A对象,从那时起,所有 你有一个A对象。任何将其用作B的尝试 对象是未定义的行为。 (当然,如果你真的 需要破坏B中创建的A::operator new,你不能 因为你已经覆盖了它。

最后:您不必将operator new声明为static; 它隐含着,并且不写static而不是惯用语 这个案例。同样,在将new B的结果分配给 一个void*,转换是惯用的,而不是惯用的 使其明确。 (最好避免使用C风格 演员,因为他们隐藏了太多错误。)