与 std::endl 的"运算符<<"不匹配,重载后

no match for ‘operator<<’ for std::endl after overload

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

很抱歉我重复了这个问题,但我没有在那里发表评论所需的声誉,那里的答案对我来说也没有说服力。

#include<iostream>
class my_ostream : public std::ostream
{
public:
std::string prefix;
my_ostream():prefix("*"){}
my_ostream& operator<<(const std::string &s){
std::cout << this->prefix << s;
return *this;
}
};
int main(){
my_ostream s;
std::string str("text");
s << str << std::endl;
}

我得到了:

不匹配'operator<lt;'在's.my_ostream::运算符<lt;(((const-std::string&)((conststd::string*)(&str)))<lt;std::endl'

我不明白为什么。如果它适用于ostream,那么它应该适用于my_ostream。此程序有效:

#include <iostream>
using namespace std;
class a{};
class b:public a{};
class c:public b{};
void f(a){cout << 'a' << endl;}
void f(b){cout << 'b' << endl;}
void f(b, a){cout << "b, a" << endl;}
void f(c){cout << 'c' << endl;}
void f(c, int){cout << "c, int" << endl;}
void f(a*){cout << "pa" << endl;}
void f(b*){cout << "pb" << endl;}
void f(b*, a*){cout << "pb, pa" << endl;}
void f(c*){cout << "pc" << endl;}
void f(c*, int){cout << "pc, int" << endl;}
int main(){
a ao; b bo; c co;
f(ao); f(bo); f(co);
f(co, ao);
a *pa=new(a); b *pb=new(b); c *pc=new(c);
f(pa); f(pb); f(pc);
f(pc, pa);
return 0;}

它输出:

a
b
c
b, a
pa
pb
pc
pb, pa

所以简单的重载并不能解释这个错误。另外,我在这里不介绍模板,所以未确定的模板类型参数不应该起作用。阅读iostream代码被证明是非常困难的,所以我很感激任何见解。

简单重载确实解释了这个错误。事实上,std::cout只是使问题变得复杂。以下也不起作用:

int main(){
my_ostream s;
s << 1;
}

问题是operator <<重载实际上隐藏了为基类定义的所有重载。

粗略地说,C++在作用域解析之后进行重载解析。因此,C++首先检查类的作用域中是否定义了operator <<。有!因此,它停止搜索更通用的函数,只考虑已经找到的函数来解决过载问题。遗憾的是,对于std::string,只有一个过载,因此调用失败。

这可以简单地通过将operator <<定义为自由函数而不是成员函数来解决:

my_ostream& operator<<(my_ostream& out, const std::string &s) {
std::cout << out.prefix << s;
return out;
}

……但这当然只解决了一些问题,因为你的类定义在语义上是错误的;不能像这样对IO流进行子类化。在这里,我的知识失败了,但我认为为了执行您想要的操作,您应该覆盖流缓冲区的uflow函数。

解决此问题的另一种方法是声明为友元运算符<lt;过载。

class my_ostream : public std::ostream
{
public:
std::string prefix;
my_ostream():prefix("*"){}
template <class T>
friend my_ostream& operator<<(my_ostream& my_os, const T& s){
std::cout << my_os.prefix << s;
return my_os;
}
};