In the comments to the OP, @dave made a suggestion to declare the destructors in your pure interfaces to be protected
instead of public
. This would outright prevent external code (that is, external to implementation classes) from invoking delete
.
For example:
class IFoo
{
protected:
virtual ~IFoo() { }
public:
virtual void release() = 0;
};
class Foo : public IFoo
{
public:
void release() override
{
delete this;
}
};
IFoo* createFoo()
{
return new Foo();
}
int main()
{
auto foo = createFoo();
foo->release(); // Expected
delete foo; // Cannot access protected destructor of IFoo
Return 0;
}
Since your factory functions only expose the pure interfaces, this approach doesn't break down if an implementation class happens to provide a public destructor. If Foo
declared a public destructor, a compiler error would still occur in main
because main
doesn't know that it's actually dealing with a Foo
.