4

我正在尝试制作一个控制台类。我想将cinand包装cout在类中并重载<<and>>运算符。所以我可以这样使用这个类:

// 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 类用作cinand cout

4

5 回答 5

7

我有一个可以处理流操纵器的工作代码。你可以在这个 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 作为起点。

于 2012-09-15T03:48:33.967 回答
2

这不是您问题的直接答案,但也许我会为您指出一些替代方案。

请参阅我对其他问题的回答。定义所有这些<<>>操作符并不是很容易。但是,您可以覆盖控制台的 streambuf。使用 cin 和 cout 的组合流缓冲区,

std::iostream从您的控制台和您的 streambuf派生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; 
};
于 2012-09-15T00:04:37.180 回答
2

我不知道为什么要做这样的事情,但它不是您需要捕获的流,而是另一种类型。但如果这只是为了让 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";
于 2012-09-14T23:06:33.113 回答
1

与上面的许多答案相反,使用模板的魔力做你想做的事情非常简单。

我建议使用字符串流,因为使用 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 一样,当然除了有更多的控制权。如果您想要二进制 I/O,您可以使用 basic_ostream 和 basic_istreams,但除非您真的需要,否则我建议您不要使用它。

于 2012-09-15T02:05:58.690 回答
-1

Overloaded operator functions must be declared with the specific types you're going to call them with on the left and right. So you will need an operator<< (int), operator<< (double), operator<< (const std::string &), etc.

If you're really just going to pass them on to cin and cout, you can save typing by using a template member function, like:

template <class T> Console& operator<< (const T& x) { cout << x; return *this; }

[thanks to André for pointing out it should return Console& so you can string together calls like Console << a << b; ]

于 2012-09-14T23:10:14.453 回答