我编写了一个自定义流类,它输出缩进文本,并且具有可以更改缩进级别的操纵器。所有缩进工作都在自定义流缓冲类中实现,该类由流类使用。缓冲区正在工作(即文本在输出中缩进),但我无法让我的操纵器工作。我在很多地方读过ostream(我的类扩展)如何重载运算符<<像这样:
ostream& ostream::operator << ( ostream& (*op)(ostream&))
{
// call the function passed as parameter with this stream as the argument
return (*op)(*this);
}
这意味着它可以将函数作为参数。那么为什么我的“缩进”或“deindent”流功能不被识别?我确定我必须对运算符&lt;&lt;进行一些重载,但我不应该不需要吗?请参阅下面的代码:
#include <iostream>
#include <streambuf>
#include <locale>
#include <cstdio>
using namespace std;
class indentbuf: public streambuf {
public:
indentbuf(streambuf* sbuf): m_sbuf(sbuf), m_indent(4), m_need(true) {}
int indent() const { return m_indent; }
void indent() { m_indent+=4; }
void deindent() { if(m_indent >= 4) m_indent-= 4; }
protected:
virtual int_type overflow(int_type c) {
if (traits_type::eq_int_type(c, traits_type::eof()))
return m_sbuf->sputc(c);
if (m_need)
{
fill_n(ostreambuf_iterator<char>(m_sbuf), m_indent, ' ');
m_need = false;
}
if (traits_type::eq_int_type(m_sbuf->sputc(c), traits_type::eof()))
return traits_type::eof();
if (traits_type::eq_int_type(c, traits_type::to_char_type('\n')))
m_need = true;
return traits_type::not_eof(c);
}
streambuf* m_sbuf;
int m_indent;
bool m_need;
};
class IndentStream : public ostream {
public:
IndentStream(ostream &os) : ib(os.rdbuf()), ostream(&ib){};
ostream& indent(ostream& stream) {
ib.indent();
return stream;
}
ostream& deindent(ostream& stream) {
ib.deindent();
return stream;
}
private:
indentbuf ib;
};
int main()
{
IndentStream is(cout);
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << deindent << endl;
return 0;
}
谢谢!
答案 0 :(得分:4)
您的操纵器应声明为只接受ostream&
类型的一个参数的函数。但是,如果您将其设为成员函数,则您知道还有一个隐式this
参数也传递给该函数。
因此,您应该将操纵器声明为免费的非成员函数,使其成为类的friend
,以便它可以访问其私有成员ib
:
class IndentStream : public ostream {
public:
IndentStream(ostream &os) : ib(os.rdbuf()), ostream(&ib){};
ostream& indent(ostream& stream) {
ib.indent();
return stream;
}
friend ostream& deindent(ostream& stream);
// ^^^^^^
private:
indentbuf ib;
};
ostream& deindent(ostream& stream)
{
IndentStream* pIndentStream = dynamic_cast<IndentStream*>(&stream);
if (pIndentStream != nullptr)
{
pIndentStream->ib.deindent();
}
return stream;
}
int main()
{
IndentStream is(cout);
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << deindent << endl;
is << "31 hexadecimal: " << hex << 31 << endl;
return 0;
}
或者,如果您真的希望自己的功能成为会员,则可以将其设为static:
class IndentStream : public ostream {
public:
IndentStream(ostream &os) : ib(os.rdbuf()), ostream(&ib){};
ostream& indent(ostream& stream) {
ib.indent();
return stream;
}
static ostream& deindent(ostream& stream)
{
IndentStream* pIndentStream = dynamic_cast<IndentStream*>(&stream);
if (pIndentStream != nullptr)
{
pIndentStream->ib.deindent();
}
return stream;
}
private:
indentbuf ib;
};
但是,这会强制您使用限定名称来引用它:
int main()
{
IndentStream is(cout);
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << IndentStream::deindent << endl;
// ^^^^^^^^^^^^^^
is << "31 hexadecimal: " << hex << 31 << endl;
return 0;
}