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;
}
A
的定义不能更改,其析构函数不是virtual
;因此,B
的对象不应被指向A
的指针删除。
我不能使用struct B : protected A {};
,因为我希望B
继承public
的所有A
成员并使他们保持public
不变。
在C++'s mixin patterns中,这是一个常见问题:
这是可以的,除非通过指向原始类的指针以多种方式删除了mixin类。
我的问题:
如何防止通过指向其父类型的指针删除对象?
答案 0 :(得分:1)
使A的析构函数受到保护,然后子类可以将其访问到类型B正确的销毁对象,但其他位置不可访问。
struct A
{
protected:
~A() {}
};
struct B : A
{
};
int main()
{
A* p_base = new B();
delete p_base; // This is now an error
}
如果您确实无法更改A,则可以执行以下操作:
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?
}
如果您通过A而不是AA删除,则无法使用。
根据问题的性质,您可以执行'#define AA'或其他类似的丑陋骇客操作,以使之与现有代码库一起使用。
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?
}
答案 1 :(得分:1)
简短的答案是你做不到。
考虑这样的功能
// definition of struct A
void func(A *p)
{
delete p;
}
和另一个编译单元中的调用者
// definitions of struct A and B as in question
void func(A *);
void caller()
{
func(new B);
}
在这种情况下,func()
中的代码完全看不见类型B
,更不用说它收到的指针p
实际指向{{1}的可能性了。 }。由于B
进行了func()
,因此函数delete p
导致caller()
的行为不确定。
在这种情况下,真正的解决方案是func()
不应从B
继承。事实上,A
没有A
析构函数的事实已经很明显。这样可以防止virtual
用caller()
调用func()
。
如果您希望B *
提供与B
相同的接口,则需要使用composition并定义A
的所有成员函数,以便它们转发到包含的{{1 }}。例如;
B
很明显,如果可以修改A
,则有可用的选项,但是问题明确指出了不可能的用例。