其他分享
首页 > 其他分享> > c-为自定义流类编写操纵器

c-为自定义流类编写操纵器

作者:互联网

我编写了一个自定义的流类,该类输出缩进的文本,并且具有可以更改缩进级别的操纵器.所有缩进工作都是在自定义流缓冲区类中实现的,该类由流类使用.缓冲区正在工作(即,文本在输出中缩进了),但是我无法使操纵器工作.我在很多地方都读到ostream(我的课程扩展了)如何使运算符超载<<像这样:

ostream& ostream::operator << ( ostream& (*op)(ostream&))

{
    // call the function passed as parameter with this stream as the argument
    return (*op)(*this);
}

这意味着它可以将函数作为参数.那么,为什么不能识别我的“缩进”或“去定”流函数呢?我确定我必须对operator<<进行一些重载,但是我不是不需要吗?请参阅以下代码:

#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;
}

谢谢!

解决方法:

您的操纵器应声明为仅接受ostream&类型的一个参数的函数.但是,如果将其设为成员函数,则您也知道该参数也隐式地传递给函数.

因此,您应该将操纵器声明为一个免费的非成员函数,使其成为您的类的朋友,以便它可以访问其私有成员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;
}

另外,如果您确实希望函数成为成员,则可以将其设为静态:

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;
}

标签:c,operator-overloading,iostream,streambuf
来源: https://codeday.me/bug/20191013/1909035.html