防止继承operator new和delete

时间:2011-08-25 10:55:50

标签: c++ inheritance operator-overloading

(我确实扫描了,但是找不到任何类似的东西,如果请尽快关闭)。

有没有办法防止这两个运营商被继承?例如:

struct foo{
  static void* operator new(std::size_t) { 
    // special
  }
  static void operator delete(void* p, std::size_t) { 
    // special
  }
};    

struct bar : public foo {
};

现在bar将继承这两个运算符 - 在这个微不足道的情况下,如果foobar中有数据成员,那么问题就不会出现了问题。 case,因为foo的分配需要以bar的方式完成!)现在避免这种情况的方法是在bar中,我也会实现运算符。但是,如果有很多派生类型,那么忘记覆盖某个地方的可能性是非常有可能的。所以问题是,有没有办法阻止这些运营商被继承?

注意:c ++ 03(如果特定于gcc,愿意接受一些编译器特定的解决方案)

6 个答案:

答案 0 :(得分:3)

Scott Meyers对这种情况有一个很好的答案:添加尺寸检查!

struct Foo
{
  static void * operator new(std::size_t n)
  {
    if (n != sizeof(Foo))  // subsumes check for n == 0
    {
      return ::operator new(n);
    }
    // your code here
  }
}

您可以根据需要自定义行为,例如如果大小错误等,则中止。这样,您可以获得任何您可能不知道的派生类的默认解决方案,但仍然只为基类本身启用了自己的操作符。

请注意,如果层次结构中的任何类为空,则上述代码可能不按预期运行。

答案 1 :(得分:3)

您可以定义一个中间foo,它再次调用global new / delete并从中派生。

class foo_without_new : public foo
{
protected: 
 foo_without_new(){} // only derived types should be able to construct foo_without_new!
public:    
 void *operator new(size_t sz) 
 { 
     return ::operator new(sz);
 }
 void operator delete(void*p) 
 { 
     return ::operator delete(p);
 }
}; 

class Bar : public FooWithoutNew
{
};

如果你必须转发构造函数,还需要做更多的工作。

答案 2 :(得分:1)

也许我错过了一些东西,但是将它们声明为私有方法呢?

答案 3 :(得分:1)

运算符new和delete are not member functions - 它们是静态的 - 它们不能被继承或阻止继承。

看起来像一样继承的原因是,重载解析在以下代码段中优先于Base::operator new,因为它比全局运算符更具体。

#include <iostream>

struct Base {
    int x;
    void * operator new (unsigned int s) {
        std :: cout << "Base\n";
        return :: operator new (s);
    }
};

struct Derived : public Base {
};

int main () {
    new Base ();
    new Derived ();
}

// Prints "Base\nBase\n"

为了防止这种情况,您必须

  • 提供另一个更具体的重载,或
  • 请勿使用operator new

我知道这不是很有帮助,但这是唯一的方法。其他“解决方案”是hackey,并且如果操作员有意义,则会隐瞒其含义 - 请参阅链接的GOTW,了解这可能是多么容易出错。

答案 4 :(得分:0)

嗯,这是继承的原则。 bar继承了foo的行为。 在bar

中再次重载这些运算符会令人满意吗?
struct foo{
    static void* operator new(size_t) { 
       // special
    }

    static void operator delete(void* p, size_t) { 
       // special
    }
};    

struct bar : public foo {
    static void* operator new(size_t s) { 
       return ::operator new (s);
    }

    static void operator delete(void* p, size_t s) { 
       ::operator delete (p);
    }
};

我试过,它工作正常。唯一的问题可能在那里:

bar * pbar = new bar(); // this is ok
foo * phaha = pbar;
delete phaha;           // this is not (foo:operator delete(void*, size_t) is called)

答案 5 :(得分:0)

  如果foo和bar中有数据成员,则会出现问题

我认为这种恐惧是错误的。因为new/deletestatic函数;所以即使你有数据成员,他们也不会影响。让运营商正常继承。此外,你无法阻止继承它们。

修改:从您的评论中,我了解到您有真实案例,您可能希望以某种方式阻止newdelete被传播。下面有一个解决方法。

  struct foo;
  template<typename T>
  T* New { return ::operator new T; }
  template<>
  foo* New<foo> { return new foo; }

  struct foo{
  template<class T> friend T* New();
  private:
  static void* operator new(size_t) { 
     // special
  }
};

以上是伪代码。我们的想法是创建一个类似New的包装器,并将其用作New<foo>()New<bar>();因此,将始终调用new的正确版本。与delete相同。