Question

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?

Was it helpful?

Solution

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 a Literal value, if you have a reference to a Literal which is really a PositiveLiteral, 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 a Literal. It is not the case that a mutable PositiveLiteral is a mutable Literal.

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. :-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top