运算符重载,但仍然"与运算符不匹配"错误

Overloaded operator, but still "no match for operator" error

本文关键字:运算符 不匹配 错误 重载      更新时间:2023-10-16

我有一个重载输出运算符"<<"的类,我已经这样实现了它。但是,编译者抱怨主方法中的"与运算符<<不匹配"。我不知道为什么它不起作用。

/*
 * Accumulator.cpp
 *
 *  
 *      
 */
#include <iostream>
#include "Accumulator.h"
using namespace std;

Accumulator::~Accumulator() {
    // TODO Auto-generated destructor stub
}
void Accumulator::operator+=(const int nbr) {
    nbrs.push_back(nbr);
}
void Accumulator::undo() {
    if (!comitted) {
        nbrs.pop_back();
    }
}
void Accumulator::commit() {
    lastCommit = nbrs;
    comitted = true;
}
void Accumulator::rollback() {
    nbrs = lastCommit;
}
ostream& Accumulator::operator<<(ostream &out, const Accumulator &accum){
    int sum = 0;
    for(int nbr : nbrs){
        sum+= nbr;
    }
    out << sum;
    return out;
}
int main() {
    Accumulator accum;
    char cmd;
    while (cin >> cmd) {
        switch (cmd) {
        case 'p':
        cout << "Sum is now " << accum << endl;
        break;
        case 'a': {
            int nbr;
            cin >> nbr;
            accum += nbr;
            break;
        }
        case 'u':
        accum.undo();
        break;
        case 'c':
        accum.commit();
        break;
        case 'r':
        accum.rollback();
        break;
    }
}
}

非静态成员函数始终有一个额外的隐藏参数,即this指针,即调用函数的对象。假设您有这样的类:

class Test {
    public:
        void f(int param) {
        }
};
Test t;
t.f(10);

调用t.f(10)基本上等效于后台的类似内容:Test::f(&t, 10)(请注意,这不是有效的代码,只是为了让您了解会发生什么)。

现在回到你的运算符,如果你把它作为类中的一个成员函数,那么你就不能像往常一样调用它。那是因为这样称呼它:

std::cout << accum;

相当于这个:

cout.operator<<(accum);

在后台相当于这个:

Accumulator::operator<<(&cout, accum);

而您的成员函数等效于以下内容:

ostream& operator<<(Accumulator* this, ostream &out, const Accumulator &accum);

请注意,参数不匹配。

因此,正确重载operator<<的唯一方法是使其成为自由函数:

class Accumulator {...};
ostream& operator<<(ostream &out, const Accumulator &accum);

这样,像这样的正常调用:

std::cout << accum;

相当于这个:

operator<<(std::cout, accum);

这与重载的声明完全匹配。

如果在重载实现中需要访问Accumulator类的私有成员,可以通过不同的方式执行此操作:例如,使重载成为类的好友,或者在类中添加一个公共函数,如下所示:

class Accumulator {
public:
    void printToStream(ostream &out) const {
        out << private_members;
    }
};

并从运算符重载调用它,如下所示:

ostream& operator<<(ostream &out, const Accumulator &accum) {
    accum.printToStream(out);
    return out;
}

现在,您不必再让超载成为类的朋友了。

正如 @n.m. 所建议的,流注入器不能作为成员函数重载,而是作为 2 个参数的普通函数。

您的 .h 文件变为:

class Accumulator {
   ... // no operator << here !
};
ostream& operator << (ostream &out, const Accumulator& accum);

和实施:

ostream& operator << (ostream &out, const Accumulator& accum) {
    ...
    return out;
}   

如果您正在编写自定义ostream类(例如专用记录器),则只会使用一个参数成员函数重载。