如何防止通过指向其父类型的指针删除对象?

时间:2020-05-09 05:02:47

标签: c++ oop design-patterns polymorphism virtual-destructor

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类。

我的问题:

如何防止通过指向其父类型的指针删除对象?

2 个答案:

答案 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析构函数的事实已经很明显。这样可以防止virtualcaller()调用func()

如果您希望B *提供与B相同的接口,则需要使用composition并定义A的所有成员函数,以便它们转发到包含的{{1 }}。例如;

B

很明显,如果可以修改A,则有可用的选项,但是问题明确指出了不可能的用例。