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)’
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.
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;
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 :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With