(我确实扫描了,但是找不到任何类似的东西,如果请尽快关闭)。
有没有办法防止这两个运营商被继承?例如:
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
将继承这两个运算符 - 在这个微不足道的情况下,如果foo
和bar
中有数据成员,那么问题就不会出现了问题。 case,因为foo
的分配需要以bar
的方式完成!)现在避免这种情况的方法是在bar
中,我也会实现运算符。但是,如果有很多派生类型,那么忘记覆盖某个地方的可能性是非常有可能的。所以问题是,有没有办法阻止这些运营商被继承?
注意:c ++ 03(如果特定于gcc,愿意接受一些编译器特定的解决方案)
答案 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/delete
是static
函数;所以即使你有数据成员,他们也不会影响。让运营商正常继承。此外,你无法阻止继承它们。
修改:从您的评论中,我了解到您有真实案例,您可能希望以某种方式阻止new
和delete
被传播。下面有一个解决方法。
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
相同。