【问题标题】:Return type is not identical to nor covariant with return type (operator++)返回类型与返回类型不同也不协变(运算符++)
【发布时间】:2024-01-20 03:20:01
【问题描述】:

我有以下错误:
IntelliSense:返回类型与被覆盖的虚函数“Counter::operator++”的返回类型“Counter”不同,也不协变

这是我的项目的标题。
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;

};

以及实施
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;
}

我收到错误:
error C2555: 'LimitedCounter::operator ++': 覆盖虚函数返回类型不同,并且与 'Counter::operator ++' 不协变

当我在 counter.hpost-increment 中删除 virtual 时,完全没有错误。因此,预增量一切正常。所以我不知道是不是因为我如何实现后增量?而且当我覆盖后增量( operator++(int) )时,我这样写是否正确:

Counter::operator++(0);

谢谢你帮助我。

【问题讨论】:

  • 多态性不能很好地与某些事物混合。如果您在指向LimitedCounter 对象的Counter 引用上调用op++,调用者代码如何知道要保留多少空间? Counter 对象足够了,还是什么?
  • 这是一个不真实的实现细节——如果编译器真的想要的话,它可以很容易地透明地间接。真正的问题是它是一个计数器值,因此不能是 LimitedCounter 或任何东西,除了计数器。

标签: c++ inheritance polymorphism operator-overloading virtual


【解决方案1】:

问题很简单:你是按值返回一个对象,所以你有以下情况

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

现在,由于方法是virtual,因此在运行时根据您调用它的对象的 vtable 选择正确的实现。

这意味着编译器无法先验地知道operator++ 返回的类型,但他至少需要知道它的大小,因为它是一个值(而不仅仅是一个指针)。

确实如果你有以下情况会被接受:

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

因为在任何情况下运行时实现都会返回一个指针,以便编译器能够正确处理它。

该标准规定了 §10.3 (C++11) 中允许和考虑的协变:

覆盖函数的返回类型应与被覆盖函数的返回类型相同或与函数的类协变。如果函数 D::f 覆盖函数 B::f,则函数的返回类型是协变的,如果它们满足以下条件:

  • 都是指向类的指针,都是对类的左值引用,或者都是对类的右值引用

  • B::f返回类型中的类与D::f返回类型中的类是同一类,或者是返回类型中的类的明确且可访问的直接或间接基类D::f

  • 指针或引用都具有相同的 cv 限定,并且 D::f 的返回类型中的类类型具有与返回类型中的类类型相同或更少的 cv 限定B::f.

【讨论】:

  • 您好,我尝试按照您的建议进行更改。 Counter* Counter::operator++(int) { Counter old = *this; count++; return &amp;old; } 。还有在 LimitedCounter 中。我执行 LimitedCounter lc(3, 5); cout &lt;&lt; counterA++ &lt;&lt; endl; 。它不打印 3,而是打印计数器的地址。抱歉我的愚蠢问题。
【解决方案2】:

这样的问题有几种不同的解决方法

  1. 只需将所有东西都放在一个类中。你真的需要 2 个计数器类而不是一个可以用计数器 strategy 参数化的类(可以从简单的 enum 到一些复杂的类)

    enum class CountinngStretegy { Unlimited, Limited}
    class Counter {
    public:
        Counter(CountinngStretegy strategy);
        //...
    }
    
  2. 使Counter 独立于LimitedCounter。然后,如果您想对计数器类型进行参数化,请使用模板:

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

【讨论】:

  • 嗨,因为在这种情况下我必须使用 2 个不同的计数器(只是为了锻炼)。不过谢谢你的建议。