Я пытаюсь сделать класс консоли. Я хотел бы завернуть cin
а также cout
в классе и перегрузить <<
а также >>
операторы. Так что я мог бы использовать класс как таковой:
// Output
Console << "Call cout from Console" << endl;
// Input
string str;
Console >> str; // Call cin
Мое лучшее предположение было:
class Console {
//...
public:
ostream& operator<< (ostream& os)
{
cout << os;
return &cout;
}
//...
};
Но я знаю, что это неправильно, как я могу перегрузить операторы, чтобы использовать класс Console в качестве обоих cin
а также cout
?
Я получил рабочий код, который может обрабатывать потоковые манипуляторы. Вы можете увидеть мой код в действии на этой странице Ideone
Вот код:
#include <iostream>
typedef std::ostream& (*manip) (std::ostream&);
class console {
};
template <class T> console& operator<< (console& con, const T& x) { std::cout << x; return con; }
template <class T> console& operator>>(console& con, T& x) { std::cin >>x; return con; }
console& operator<< (console& con, manip manipulator){ std::cout<<manipulator; return con;}
int main() {
console c;
int a,b;
c>>a>>b;
c << "hello world"<<std::endl<<std::hex<<(a+b)<<std::endl;
}
Спасибо @MooingDuck за обсуждение, которое привело меня к рабочему ответу, и @ 111111 за начальную точку.
Я не знаю, почему хотел бы сделать такую вещь, но это не поток, который вам нужно захватить, а другой тип. Но если это просто для того, чтобы сделать std :: cout и std :: cin более удобными, я бы не стал беспокоиться.
class console {
};
template<typename T>
console& operator<<(console con, const T& val) {
std::cout << val;
return con;
}
console c;
c << "hello world\n";
Это не прямой ответ на ваш вопрос, но, возможно, я укажу вам какую-то альтернативу.
См мой ответ на какой-то другой вопрос. Чтобы определить все это <<
а также >>
Операторы это не очень просто. Однако вы можете перезаписать streambuf для консоли. Используйте комбинированные потоковые буферы cin и cout,
Получите вашу консоль от std::iostream
и ваш поток из std::streambuf
class console_streambuf : public std::streambuf {
public:
console_streambuf() {
// no buffering, overflow on every char
setp(0, 0);
}
virtual int_type overflow(int_type c) {
std::cout << c;
return c;
}
...
};
class console : public std::iostream {
public:
console() { rdbuf(&buf); }
private:
console_streambuf buf;
};
Вопреки многим ответам выше, делать то, что вы хотите, довольно просто, используя магию шаблонов.
Я бы порекомендовал использовать струнный поток, потому что использование ostream (cout — ostream) может потребовать чародейской черной магии (без шуток).
#include <string>
#include <iostream>
#include <sstream>
struct console {
std::stringstream data_;
console() : data_() { };
// We make ourselves a template sink so we can "take" operator<<'s.
// The awesome advantage to using a template like this is that the
// compiler will allow us to "take" any data that can be converted
// to a stringstream, which will handle converting int's etc.
// for us!
template<typename T>
console& operator<<(const T& what) {
data_ << what;
return *this; // We must return a reference if we want to
// string together more than one thing, i.e.
// b << " " << 4;
}
void flush() {
std::cout << data_.str();
data_.clear();
std::cout.flush();
}
};
int main()
{
int a = 4;
console b;
console c;
b.data_ << 2;
c.data_ << 4;
//b << std::cout; // WHAT? it's possible but stupid, prints garbage
// Because we made the template return a reference, this will
// allow us to chain things just like we do with cout.
b << " HELLO WORLD! " << "yo!" << 4;
b << a << " " << 4.2f;
// Compiler chokes on this. It will try to convert "console"// to a stringstream which it can't.
//b << c;
b.flush(); // Send out the output
// Wait for key press
char foo[500];
gets(foo);
}
Выход:
2 HELLO WORLD! yo!44 4.2
Точно так же, как cout, за исключением, конечно, с большим контролем.
Вы можете начать использовать basic_ostream’s и basic_istreams, если хотите использовать бинарный ввод / вывод, но я бы рекомендовал против этого, если вам это действительно не нужно.
Перегруженные операторные функции должны быть объявлены с конкретными типами, с которыми вы будете вызывать их слева и справа. Так что вам понадобится operator<< (int)
, operator<< (double)
, operator<< (const std::string &)
, так далее.
Если вы действительно просто собираетесь передать их в cin и cout, вы можете сохранить ввод с помощью функции-члена шаблона, например:
template <class T> Console& operator<< (const T& x) { cout << x; return *this; }
[спасибо Андре за то, что он указал, что должен вернуть Консоль& так что вы можете связать вместе звонки, как Console << a << b;
]