I'm sorry if this question has been asked before, I tried hard to find something like it, but I wasn't even sure what to search for.
Suppose I have following interface (this is just an example, my specific case have nothing to do with operators or addition) :
class AddAndSub
{
public:
virtual AddAndSub operator +(AddAndSub const &) = 0;
virtual AddAndSub operator -(AddAndSub const &) = 0;
}
Since a + b
can be expressed as a - (-b)
and a - b
as a + (-b)
(for simplicity let's assume negation is well defined for all deriving types) my first instinct was to simulate this property in the implementation, so only one of the operators need to be explicitly defined:
class AddAndSub
{
public:
virtual AddAndSub operator +(AddAndSub const & b)
{
return *self - (-b);
}
virtual AddAndSub operator -(AddAndSub const & b)
{
return *self + (-b);
}
}
However I'm not fully satisfied with my solution, since I'm still required to define at least one of the operations, but it's not explicitly enforced by the code and forgetting to define one results in very undescriptive error message "Stack overflow". I can leave the interface as it is in the first example to make sure every class implementing it defines required methods, but that in turns results in a lot of redundant code in non-tivial cases.
Is there a proper way to reduce code redundancy in situations like this while still keeping the compile time checks and leaving choice of which methods to implement to the interface user?
PS: I know I can just make one of those methods pure virtual but then I can't choose which method I can define in a case when it would be harder to implement addition than subtraction (which TBH is just a minor nitpick, but I'm still wondering if there is a better way).
It's better to keep your interface purely abstract. If you want to implement operator-() in terms of operator+() or vice versa, do that in your implementation class(es).
If for some reason you really want to minimize the number of methods your implementation class(es) have to override, consider creating a helper class that subclasses your interface and implements some methods in terms of others. You can mark those methods as final (a C++11 feature) to forbid them from being overridden again by your implementation class, which would be subclassing the helper one.