Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

overriding pure virtual operators

I'm trying to create a counter interface that forces all derived classes to implement this interface:

class CounterInterface 
{ 
public:
  virtual CounterInterface& operator ++ () = 0;
  virtual CounterInterface  operator ++ (int) = 0;
  virtual CounterInterface& operator -- () = 0;
  virtual CounterInterface  operator -- (int) = 0;
  virtual bool operator == ( const CounterInterface o ) const   = 0;
  virtual operator uint32_t () const = 0;
  virtual void reset() = 0;
};

However, just including this class definition results in the error below.

Unfortunately post inc can't be defined as reference.

Any ideas how to resolve this chicken/egg problem?

CounterInterface.h:25:29: error: invalid abstract return type for member function ‘virtual libceis::CounterInterface libceis::CounterInterface::operator++()’
CounterInterface.h:22:8: note:   because the following virtual functions are pure within ‘libceis::CounterInterface’:
CounterInterface.h:25:29: note:   virtual libceis::CounterInterface libceis::CounterInterface::operator++()
CounterInterface.h:26:29: note:   virtual libceis::CounterInterface libceis::CounterInterface::operator++(int)
CounterInterface.h:27:29: note:   virtual libceis::CounterInterface libceis::CounterInterface::operator--()
CounterInterface.h:28:29: note:   virtual libceis::CounterInterface libceis::CounterInterface::operator--(int)
CounterInterface.h:29:17: note:   virtual bool libceis::CounterInterface::operator==(libceis::CounterInterface) const
CounterInterface.h:30:12: note:   virtual libceis::CounterInterface::operator uint32_t() const
CounterInterface.h:31:17: note:   virtual void libceis::CounterInterface::reset()
CounterInterface.h:26:29: error: invalid abstract return type for member function ‘virtual libceis::CounterInterface libceis::CounterInterface::operator++(int)’
like image 691
user1903875 Avatar asked Dec 14 '12 12:12

user1903875


3 Answers

You're out of luck. You want to return a value with the dynamic type of the object the function is called on. You can't: (non-pointer) values in C++ can't be covariant return types because a return-by-value in C++ can't have a different dynamic type from its static type.

It's basically the same problem as implementing a virtual clone(). It can't return by value. You'd be in trouble even if CounterInterface wasn't an abstract class, but instead of noticing it when the code fails to compile, you'd notice it when the returned object gets sliced.

What you could do is expand on the design. Write a class that holds a (smart) pointer to an instance of CounterInterface. This type can be returned by value and hence can implement the interface you want. It can do that by calling a pure virtual function CounterInterface *clone() (or unique_ptr<CounterInterface> clone()) that allocates and returns a new instance of the concrete class that implements the interface. For the operators that do work as virtual functions, you can leave them on CounterInterface and your wrapper class can call through, or you can rename them in the virtual interface:

class Counter {
    unique_ptr<CounterInterface> ctr;
  public:
    Counter(unique_ptr<CounterInterface> c) : ctr(std::move(c)) {}
    Counter(CounterInterface *c) : ctr(c) {}
    Counter &operator++() { 
        ctr->increment(); // or ++(*ctr)
        return *this; 
    }
    Counter operator++(int) {
        Counter ret(ctr->clone());
        ctr->increment();
        return ret;
    }
    operator uint32_t() const {
        return *ctr;
    }
    void reset() {
       return ctr->reset();
    }
};

Virtual operator== is a whole separate problem which I'll leave to other questions on the site.

Btw, CounterInterface needs a virtual destructor.

like image 104
Steve Jessop Avatar answered Nov 09 '22 19:11

Steve Jessop


You cannot instantiate a class with pure virtual member functions. Since you cannot create them, you also cannot return them by value, as you do in

virtual CounterInterface  operator ++ (int) = 0;
virtual CounterInterface  operator -- (int) = 0;
like image 29
Olaf Dietsche Avatar answered Nov 09 '22 18:11

Olaf Dietsche


First of all you shall replace

virtual bool operator == ( const CounterInterface o ) const   = 0;

by

virtual bool operator == ( const CounterInterface &o ) const   = 0;

Secondly, the same thing that said 'Olaf Dietsche', it was faster than me :-)

like image 23
benjarobin Avatar answered Nov 09 '22 19:11

benjarobin