Search code examples
c++polymorphismoperator-overloadingabstract-classfriend

Virtual-like friend functions?


I want to create interface like

class Scalar {
public:
  Scalar() {}
  virtual ~Scalar() {}
  //virtual members operators
  virtual Scalar& operator+() const = 0;
  virtual const Scalar operator-() const;
  virtual Scalar& operator=() = 0;
  virtual Scalar& operator+=() = 0;
  //...
};

I intend also to use some friend functions, for example:

    friend const Scalar operator+(const Scalar&, const Scalar&);

But there is a problem when I derive the abstract class, and create derived class, say:

class RealNumber: public Scalar {
public:
  friend const RealNumber operator+(const RealNumber&, const RealNumber&);
  //some definitions...
};

According to this logic, I would need to define a new overload of friend operator+ for every new class derived from Scalar. Is there some way to solve this problem and avoid declaring these friends in all the derived classes?


Solution

  • Is this your problem ?

    I understand that your problem is that your two friends refer to totally different functions, since they have a different signature:

    friend const Scalar operator+(const Scalar&, const Scalar&);
    friend const RealNumber operator+(const RealNumber&, const RealNumber&);
    

    Worse, the choice of a class external friend will not be polymorphic: the right friend will be chose based on the compile-time type.

    How to solve it ?

    First of all, instead of using an outside overloaded friend, you could consider overriding the operator of the class itself (keeping the signature identical).

    However this has two major challenges:

    • it is almost impossible to return a reference from arithmetic operator, unless you'd accept side-effects, which would then make your operator behave differently than expected.
    • you'd need to cope with combining different kind of scalars: what if you'd have to add a Scalar to a RealNumber ? This would require a double dispatch to be implemented to cope with all the possible combination.

    So, dead-end ?

    No, there are two other alternatives, depending on your real problem:

    • Do you really want to combine arithmetic type dynamically at run-time ? If yes, you need to go away from the C++ operator overriding approach, and implement an expression evaluator, using the interpreter pattern.
    • If not, consider to use a template based design, so that the compiler choses at compile-time the appropriate specialisation.
    • Or suffer with the many possible friends and their combination of parameter types.