简体   繁体   中英

Return type is not identical to nor covariant with return type (operator++)

I have the following error:
IntelliSense: return type is not identical to nor covariant with return type "Counter" of overridden virtual function "Counter::operator++"

Here are the headers of my project.
counter.h

/* Header file of Counter Class*/
#pragma once
#include <iostream>
using namespace std;
//Class definition
class Counter {
    friend ostream &operator<<(ostream &out, const Counter &c);
    public:
        Counter(int n0 = 0);
        virtual Counter &operator++();
        virtual Counter operator++(int);
        void reset();
        int getCount() const;

    private:
        int count;
};

LimitedCounter.h

#pragma once
#include "counter.h"

class LimitedCounter : public Counter{
    friend ostream &operator<<(ostream &out, const LimitedCounter &c);
public:
    LimitedCounter(int low, int up);
    void reset();
    LimitedCounter& operator++();
    LimitedCounter operator++(int); // error here
    operator int() { return getCount(); };
    int getCount() const { return Counter::getCount(); };
private:
    int upper;

};

And the implementation
counter.cpp

/* Implementation of Counter Class*/

#include "counter.h"
#include <iostream>

Counter:: Counter(int n0) {
     count = n0;
}
Counter& Counter::operator++() {
   count++;
   return *this;
}
Counter Counter::operator++(int) {
   Counter old = *this;;
   count++;
   return old;
}
void Counter::reset(){
   count = 0;
}
int Counter::getCount() const{
   return count;
}
ostream &operator<<(ostream & out, const Counter &c) {
     out << "\nCounter value is now " << c.count ;
     return out;
}

LimitedCounter.cpp

#include "LimitedCounter.h"
LimitedCounter::LimitedCounter(int low, int up) : Counter(low), upper(up) {}

LimitedCounter& LimitedCounter::operator++() {
    if (getCount() < upper) {
        Counter::operator++();
    }
    return *this;
}

LimitedCounter LimitedCounter::operator++(int) {
    if (getCount() < upper) {
        LimitedCounter old = *this;
        Counter::operator++(0); // question?
        return old;
    }
    else {
        return *this;
    }
}

void LimitedCounter::reset() {
    Counter::reset();
}

//friend function
ostream &operator<<(ostream &out, const LimitedCounter &c) {
    out << c.getCount() << endl;
    return out;
}

I get the error:
error C2555: 'LimitedCounter::operator ++': overriding virtual function return type differs and is not covariant from 'Counter::operator ++'

When I remove virtual in the post-increment of counter.h then there is no error at all. So everything works fine with the pre-increment . So I don't know is it because how I implement the post-increment ? And also when I override the post-increment ( operator++(int) ), is it right that I write like this:

Counter::operator++(0);

Thanks for helping me.

The problem is simple: you are returning an object by value, so you have the following situation

virtual Counter Counter::operator++(int)
LimitedCounter LimitedCounter::operator++(int) override

Now, since the method is virtual , the correct implementation is chosen at runtime according to the vtable of the object you are calling it on.

This means that the compiler can't know a priori the type returned by operator++ but he needs to know at least its size since it's a value (and not just a pointer).

Indeed if you had the following situation would be accepted:

virtual Counter* Counter::operator++(int)
LimitedCounter* LimitedCounter::operator++(int) override

because the runtime implementation would in any case return a pointer so the compiler would be able to cope with it correctly.

The standard specifies what's allowed and considered covariant in §10.3 (C++11):

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f , the return types of the functions are covariant if they satisfy the following criteria:

  • both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes

  • the class in the return type of B::f is the same class as the class in the return type of D::f , or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f

  • both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.

It is some different ways to solve problem like this

  1. Just keep all things in one class. Do you really need 2 counter class instead of one that can be parametrized with counter strategy (that can be from simple enum to some complicated class )

     enum class CountinngStretegy { Unlimited, Limited} class Counter { public: Counter(CountinngStretegy strategy); //... } 
  2. Make Counter independent from LimitedCounter . Then if you want parametrize on counter type, use templates for that:

     template <typename SomeCounter> void do_smth_with_counter(SomeCounter counter); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM