I have a class Literal which is really just a wrapper for (const int). I want to have a second class PositiveLiteral which inherits from Literal, but has a constructor that asserts that its value is positive.
class Literal {
public:
Literal(int x):x(x){}
virtual ~Literal(){}
// Other methods
private:
const int x;
}
class PositiveLiteral : public Literal {
public:
PositiveLiteral(int x):Literal(x) {
assert(x > 0)
}
}
In this way, functions that expect a positive literal can simply take a PositiveLiteral as an argument. Then I don't need to put explicit assertions in my code and furthermore, where those assertions would fail, I can immediately see why.
I don't expect to otherwise inherit from Literal except for in this one case. Yet, because there is inheritance, I have to give Literal a virtual destructor to avoid undefined behavior which seems silly because PositiveLiteral has no exra information associated to it that Literal does not have. It's just a way to maintain an assertion without having to make it explicit.
What's another way to accomplish the same task without the need for a virtual method in what's supposed to be a simple wrapper class?
You don't need to have to have a virtual destructor unless you do dynamic allocation and
delete
via a pointer to base class.The real problem lies at the design level. For while it is true that every
PositiveLiteral
value is aLiteral
value, if you have a reference to aLiteral
which is really aPositiveLiteral
, then you can assign it a negative value…In the literature and forum discussions this was once known as the ellipse-versus-circle problem, although the similarity isn't obvious.
First, to be very clear about the problem, it's only for immutable values that a
PositiveLiteral
is aLiteral
. It is not the case that a mutablePositiveLiteral
is a mutableLiteral
.Then, a practical C++ solution is to provide value conversion instead of using inheritance.
For example, this is the solution used for smart pointers.
Addendum: I failed to see that in the OP's code the value is
const
. So there's no such problem.A practical problem is that at least one compiler, Visual C++, has a tendency to silly-warn about its inability to generate a copy assignment operator; it can be shut up by declaring a private one without implementation. :-)