【问题标题】:C++ wrapper around 2 stringstreams ("dialogue" imitation)围绕 2 个字符串流的 C++ 包装器(“对话”模仿)
【发布时间】:2013-04-21 06:14:12
【问题描述】:

我目前正在为两个流编写一个包装器。最后,我想模仿与Person 的对话,以使我的代码清晰且易于使用。

声明

class Person
{
public:
    void process();

private:
    std::stringstream _request;
    std::stringstream _response;
}

用法

Person daniel;
std::stringstream answer;
daniel << "Hello" << std::endl; // f.e std::endl means end of the phrase
daniel << "How" << "are you";
daniel << "doing?";
daniel >> answer;
daniel.process();
std::cout << "Daniel says: " << answer;
// or
std::cout << "Daniel says: " << daniel;

我觉得可以通过重载&lt;&lt;&gt;&gt;操作符来实现,但是我卡住了。我从未将流用于这些目的。我google了很多,显然还是无法理解基本的东西。

简而言之

std::ostream& operator<<(std::ostream& o, const person& p)
{
    output << p._response.rdbuf();

    return (output);
}

std::istream& operator>>(std::istream& i, person& p)
{
    p._request << i.rdbuf();
    // internal process() call probably will be better
    return (p._request);
}

确实有一些例子很棒,但我会非常高兴能有粗略的想法让我摆脱僵局。

【问题讨论】:

  • “但是我卡住了”到底是什么问题?
  • 我认为应该是这样的。不要觉得自己在这个话题上很自在。现在,编译器说:对于 person 的二进制表达式('person' 和 'const char [4]')的操作数无效

标签: c++ stl stream operator-overloading wrapper


【解决方案1】:

老实说,我不明白你为什么想要这个,但我想这是某种练习或家庭作业。无论如何,实现这个功能有一些微妙之处,我怀疑你自己无法弄清楚,所以这里是可行的解决方案。

#include <iostream>
#include <sstream>

class Person {
public:
    void process() {
        // Let's see what we've got in `_request`
        std::cout << _request.rdbuf() << std::endl;

        // Do some processing to produce correponding _response

        // In this example we hardcode the response
       _response << "I'm fine, thanks!";
    }

private:
    std::stringstream _request;
    std::stringstream _response;

    // Make them all friends so that they can access `_request` and `_response`
    friend Person& operator<<(Person& p, std::string const& s);
    friend Person& operator<<(Person& p, std::ostream& (*f)(std::ostream&));
    friend std::ostream& operator<<(std::ostream &o, Person& p);
    friend Person& operator>>(Person& p, std::string& s);
};

Person& operator<<(Person& p, const std::string& s) {
    p._request << s;

    return p;
}

// Notice this peculiar signature, it is required to support `std::endl`
Person& operator<<(Person& p, std::ostream& (*f)(std::ostream&)) {
    p._request << f;

    return p;                           
}

// Somewhat conventional stream operator overload (in terms of signature)
std::ostream& operator<<(std::ostream &o, Person& p) {
    o << p._response.rdbuf();

    return o;
}

Person& operator>>(Person& p, std::string& s) {
    // NOTE: This will read not the whole `_reponse` to `s`, but will stop on
    // the first whitespace. This is the default behavior of `>>` operator of
    // `std::stringstream`.
    p._response >> s;

    return p;
}

值得一提的是,就您要实现的功能而言,您的第一次尝试是完全错误的。这归结为这样一个事实,您似乎正在遵循有关流运算符重载的传统教程,而这里的方法应该不同以实现所需的功能。特别要注意建议的流运算符重载的签名。

此外,您必须添加更多重载以支持其他输入类型,例如 int。本质上,您必须添加更多类似于 std::basic_ostream 提供的开箱即用的重载。特别要注意最后一个:

basic_ostream& operator<<(basic_ostream& st, 
                          std::basic_ostream& (*func)(std::basic_ostream&));

这个人是来支持std::endl的。请注意,我已经为您添加了类似的重载到Person,以便std::endl 可以正常工作(见下文)。其他重载(例如原始类型)留给您作为练习。

读取响应

你一开始就想要的那个。

int main() {
    Person daniel;

    daniel << "Hello" << std::endl;
    daniel << "How " << "are you";
    daniel << " doing?" << std::endl;

    // We are ready to process the request so do it
    daniel.process();

    // And Daniel's answer is...
    std::cout << "Daniel says: " << daniel << std::endl;

    return 0;
}

阅读响应:另一种方式

这个有点笨拙和繁琐,基本上是Person&amp; operator&gt;&gt;(Person&amp; p, std::string&amp; s)重载的实现中注释的结果(见上)。

int main() {
    Person daniel;

    daniel << "Hello" << std::endl;
    daniel << "How " << "are you";
    daniel << " doing?" << std::endl;

    // We are ready to process the request so do it
    daniel.process();

    // And Daniel's answer is...
    std::string part1;
    std::string part2;
    std::string part3;

    // Will read "I'm"
    daniel >> part1;

    // Will read "fine,"
    daniel >> part2;

    // Will read "thanks!"
    daniel >> part3;

    std::cout << "Daniel says: " << part1 << " " << part2 << " " << part3 << std::endl;

    return 0;
}

【讨论】:

    【解决方案2】:

    rdbuf() 不返回字符串。您应该调用 str() 从字符串流中获取 std::string。您需要将这两个函数声明为类的朋友才能访问其私有属性。

    class Person
    {
    public:
        void process();
    
        friend std::ostream& operator<<(std::ostream& o, const person& p);
        friend std::istream& operator>>(std::istream& i, person& p);
    private:
        std::stringstream _request;
        std::stringstream _response;
    }
    
    std::ostream& operator<<(std::ostream& o, const person& p)
    {
        o << p._response.str();
    
        return (o);
    }
    
    std::istream& operator>>(std::istream& i, person& p)
    {
        i >> p._request;
        // internal process() call probably will be better
        return i;
    }
    

    【讨论】:

    • 虽然您所说的部分正确(rdbuf 的使用非常好),但最终的解决方案远不能提供所需的功能,因此,总的来说,这个答案是不正确的。有关详细信息,请参阅我的答案。
    猜你喜欢
    • 1970-01-01
    • 2011-12-14
    • 2021-03-15
    • 1970-01-01
    • 2012-04-23
    • 2014-02-07
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    相关资源
    最近更新 更多