We are wrapping an object implementing an abstract class IFunctionality, in a class we are writing that also implements IFunctionality.
IFunctionality interface is defined in third party code and at the moment it only consists of virtual functions, most of them being pure virtual. Non-pure virtual functions usually have an empty implementation and are overridden in the specific implementation.
IFunctionality does not have any member variable (at the moment).
Our wrapper looks like this:
class WrapperFunctionality : public IFunctionality
{
public:
WrapperFunctionality(IFunctionality& pOriginal)
: m_pOriginal(pOriginal)
{
}
// We override all virtual functions and forward them to the original.
void doX() override { m_pOriginal->doX(); }
void doY() override { m_pOriginal->doY(); }
// ...
// Well, except a few functions that we specialize.
// That's why we need the wrapper.
void doSomethingSpecial() override { ... }
};
All is fine at the moment. But the code could break silently in the future.
Issue 1: thirdparty code could add new non-pure virtual functions to IFunctionality. It would get undetected and we would fail to call the according function in the original object.
Issue 2: thirdpary code could add public members to IFunctionality and could directly access these members. We would also fail to forward these modifications to the original objects.
I wonder whether we could detect these issues at compile time with the help of static_assert or some template magic.
Issue 2 has been discussed in How to detect if a class has member variables? without a satisfying solution. But in my thinking, it is less likely to happen (as these third-party developers don't seem to prefer public member variables for this interface class anyway).
But issue 1 is more likely to happen. The interface class already has non-pure virtual functions and is likely to get new ones. Is there a way to enforce that my class implements all virtual functions (pure or not) from that class?
To clarify things, let me give a more concrete description of the the situation.
The interface represents a surface on which one can draw geometry with given attributes:
class ISurface
{
public:
virtual void setColor(const RGB& color) = 0;
virtual void setOpacity(float alpha) = 0;
virtual void drawLine(...) = 0;
virtual void drawCircle(...) = 0;
// etc
};
A specific ISurface implementation is instantiated by the third party framework, and there are multiple implementations of it based on the back-end.
We have many objects in our system that know how to draw themselves to an ISurface. We don't control their draw
function. The objects can be from third party plugins:
class IDrawableObject
{
public:
virtual void draw(ISurface* pSurface) const = 0;
};
Then a possible implementation of IDrawableObject, possibly from third party code:
class SomeObject : public IDrawableObject
{
public:
virtual void draw(ISurface* pSurface) const override
{
pSurface->setColor(RGB(255, 0, 0));
pSurface->drawLine(...);
pSurface->setOpacity(0.7f);
pSurface->fillCircle(...);
}
};
At some point, we want to change the visual representation of these third party objects by overriding their color or opacity. We can hook into the procedure that makes the draw call of the object:
// That function will be called by the framework
virtual void drawObjectToSurface(const IDrawableObject* pObject, ISurface* pSurface) override
{
pSurface->setColor(m_overrideColor);
pSurface->setOpacity(m_overrideAlpha);
// Next line does not work as expected, because the object
// overwrites our color and alpha before drawing itself
//pObject->draw(pSurface); // does not work
// Instead, we use a wrapper that blocks color and opacity writes
BlockingSurfaceWrapper wrapperSurface(pSurface);
pObject->draw(&wrapperSurface);
}
question from:
https://stackoverflow.com/questions/65940834/enforce-that-all-virtual-functions-from-parent-class-are-overridden-from-the-ch