Let's say we have a concrete class Apple
. (Apple objects can be instantiated.)
Now, someone comes and derives an abstract class Peach
from Apple. It's abstract because it introduces a new pure virtual function. The user of Peach is now forced to derive from it and define this new function. Is this a common pattern? Is this correct to do?
Sample:
class Apple
{
public:
virtual void MakePie();
// more stuff here
};
class Peach : public Apple
{
public:
virtual void MakeDeliciousDesserts() = 0;
// more stuff here
};
Now let's say we have a concrete class Berry
. Someone derives an abstract class Tomato
from Berry. It's abstract because it overwrites one of Berry's virtual functions, and makes it pure virtual. The user of Tomato has to re-implement the function previously defined in Berry. Is this a common pattern? Is this correct to do?
Sample:
class Berry
{
public:
virtual void EatYummyPie();
// more stuff here
};
class Tomato : public Berry
{
public:
virtual void EatYummyPie() = 0;
// more stuff here
};
Note: The names are contrived and do not reflect any actual code (hopefully). No fruits have been harmed in the writing of this question.
Re Peach from Apple:
Re Tomato from Berry:
Juice()
- imposes certain requirements and makes certain promises. Derived classes' implementations of Juice()
must require no more and promise no less. Then a DerivedTomato IS-A Berry and code which only knows about Berry is safe.Possibly, you will meet the last requirement by documenting that DerivedTomatoes must call Berry::Juice()
. If so, consider using Template Method instead:
class Tomato : public Berry
{
public:
void Juice()
{
PrepareJuice();
Berry::Juice();
}
virtual void PrepareJuice() = 0;
};
Now there is an excellent chance that a Tomato IS-A Berry, contrary to botanical expectations. (The exception is if derived classes' implementations of PrepareJuice
impose extra preconditions beyond those imposed by Berry::Juice
).