C++ 如何防止通过指向其父类型的指针删除对象?
C++ 如何防止通过指向其父类型的指针删除对象?,c++,oop,design-patterns,polymorphism,virtual-destructor,C++,Oop,Design Patterns,Polymorphism,Virtual Destructor,A的定义不能更改,其析构函数不是虚拟的;所以B的对象不应该被指向a的指针删除 我不能使用structb:protecteda{},因为我希望B继承A的所有public成员,并使其保持不变public 在中,这是一个常见的问题: 这是可以的,除非通过指向原始类的指针以多态方式删除mixin类 我的问题: 如何防止通过指向其父类型的指针删除对象?使a的析构函数受保护,则子类可以正确地访问B类型的破坏对象,但其他地方无法访问该对象 struct A {}; struct B : A { op
A
的定义不能更改,其析构函数不是虚拟的
;所以B
的对象不应该被指向a
的指针删除
我不能使用structb:protecteda{}
,因为我希望B
继承A
的所有public
成员,并使其保持不变public
在中,这是一个常见的问题:
这是可以的,除非通过指向原始类的指针以多态方式删除mixin类
我的问题:
如何防止通过指向其父类型的指针删除对象?使a的析构函数受保护,则子类可以正确地访问B类型的破坏对象,但其他地方无法访问该对象
struct A
{};
struct B : A
{
operator A() const = delete; // not work
};
int main()
{
B* p_derived = new B();
delete p_derived; // ok
// How to make the following two lines illegal?
A* p_base = new B();
delete p_base;
}
如果您真的无法更改,那么您可以这样做:
struct A
{
protected:
~A() {}
};
struct B : A
{
};
int main()
{
A* p_base = new B();
delete p_base; // This is now an error
}
但是,如果通过A而不是AA删除,则此操作不起作用
根据问题的性质,您可以使用“定义AA”或其他类似的丑恶手段来使用现有的代码库
struct A
{
};
struct AA : A
{
protected:
~AA() {}
};
struct B : AA
{
};
int main()
{
AA* p_base = new B();
delete p_base; // How to make this a compile-time error?
}
简而言之,你不能 考虑这样一个函数
struct A
{
};
struct AA : A
{
protected:
~AA() {}
};
#define A AA
struct B : A
{
};
int main()
{
A* p_base = new B();
delete p_base; // How to make this a compile-time error?
}
以及另一个编译单元中的调用者
// definition of struct A
void func(A *p)
{
delete p;
}
在这种情况下,func()
中的代码在所有类型的B
中都不可见,更不用说它接收的指针p
实际指向aB
的可能性了。由于func()
在这种情况下,真正的解决方案是B
不应从A
继承。事实上,a
没有virtual
析构函数,这已经强烈暗示了这一点。这将阻止caller()
使用B*
调用func()
如果希望B
提供与A
相同的接口,则需要使用组合,并定义B
的所有成员函数,以便它们转发到包含的A
。比如,
// definitions of struct A and B as in question
void func(A *);
void caller()
{
func(new B);
}
显然,如果结构A
可以修改,则有一些选项可用,但问题明确说明了不可能修改的用例。您打算如何删除B的实例?如果您不能更改A
,则无法实现这一点。我会重新考虑这个问题。也许B
应该“has-a”a
而不是“is-a”a
,并且删除了typecast操作符和一组引用a字段的字段。在C++的混合模式中,这是一个常见问题@user207421不,这实际上不是mixin模式的常见问题,因为mixin和多态删除在实践中很少同时出现。如果需要这样的东西,那么base/mixin可以是多态的,包括给它一个虚拟析构函数。一般来说,mixin类不打算以多态方式使用,因此它们没有虚拟析构函数,不应该以多态方式删除。如果将p\u base
传递给一个函数,该函数接受实际的a*
作为参数,然后将其删除,则最后一次宏攻击将不起作用。
struct B
{
B() : a() {};
void some_member(some_type arg)
{
a.some_member(arg); // assume A has this member that accepts these arguments
}
private:
A a;
};