Написание манипулятора для пользовательского класса потока

Я написал собственный класс потока, который выводит текст с отступом и имеет манипуляторы, которые могут изменять уровень отступа. Вся работа по отступам реализована в пользовательском классе потокового буфера, который используется потоковым классом. Буфер работает (то есть текст с отступом в выводе), но я не могу заставить свои манипуляторы работать. Я читал во многих местах, как ostream (который расширяет мой класс) перегружает оператора<< как это:

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

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

Это означает, что он может принимать функцию в качестве параметра. Так почему же не распознаются мои потоковые функции с отступом или отступом? Я уверен, что я должен сделать некоторую перегрузку оператора<<Но разве мне не нужно? Смотрите мой код ниже:

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

Спасибо!

1

Решение

Ваш манипулятор должен быть объявлен как функция, которая принимает только один аргумент типа 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;
}
4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]