为iostream和fstream同时重载<<运算符

3
我正试图对iostream中的cout和fstream中的fout同时进行重载。
ostream& operator<<(ostream& cout, const Object& obj);

ofstream& operator<<(ofstream& fout, const Object& obj);

我希望第一个函数可以在控制台上运行,以向用户提供文本;而我希望第二个函数仅将变量的值输出到文件中。
然而,在...
void save_data(const Object& obj)
{
    fstream fout("DataBase.txt", ios::out);

    if (fout.is_open())
    {
        fout << obj;
        fout.close();
    }

    else
        cout << "DataBase.txt could not be saved!" << endl;
}

我有一段文本,用于引导用户在我的文件中重载cout函数时使用。

2个回答

4

std::fstream继承自std::iostream,后者又继承自std::ostream。这个链条中没有std::ofstream,因此该重载不适合使用。

解决方法之一是在调用处使用std::ofstream而非std::fstream。您还可以为std::fstream添加一个重载。但请注意,std::ostream并不一定是控制台;这是您必须从代码的其余部分提供的保证。例如,std::ofstream可能会向上转型为std::ostream,然后用于打印一个Object,而您的重载集将假定此流用于控制台。确保代码的其余部分提供该保证可能很困难。此外,稳健地检测控制台将依赖于平台,具体答案可在本站其他位置找到(例如,Windows)。

现有程序处理此要求的一种方法是在命令行上设置明确的“交互”选项。例如,git命令使用--interactive-i。这样,用户请求额外的指导输出,而无需进行任何巧妙的检测。


他不能只使用一个std::ostream重载吗? - David G
据我所了解的要求,这些重载具有不同的输出。如果将策略更改为选择控制台还是文件,而不依赖于流的静态类型,则一个重载就足够了,尽管它仍然需要内部分支来覆盖两个输出目标。@0x499602D2 - chris
在这两个重载函数中,它们只是向流对象写入数据,对吗?那么应该只保留一个重载函数。 - David G
@0x499602D2,不,原帖作者想要在输出到控制台时获得额外的输出。"我想让第一个函数与控制台一起工作,以便为用户提供文本,而我想让第二个函数仅将变量的值输出到文件中。" 这是我的解释,也得到了问题后面的 "指导用户" 的支持。 - chris

0
感谢@chris的帮助,我终于找到了真正的问题所在。通常情况下,不需要根据基类和派生I/O流类型进行重载。通常有一种多态的方法可以实现你想要的功能。在这种情况下,您可以检查被写入的流是否为std::cout,并构造一个新的流来写入它。
std::ostream& operator<<(std::ostream& os, Obj const& obj) {
  std::ostream o(nullptr);
  if (&os == &std::cout) {
    o.rdbuf(std::cout.rdbuf());
  }
  o << "hello\n";
  return os;
}

如果缓冲区是空指针,则写入o将不起作用。这将允许您为用户编写控制台输出指南,而无需分离两个实现。

如果您仍想拆分实现,请创建两个函数,并在上述if条件为真和假时调用适当的函数。

std::ostream& write_with_console_o(std::ostream&);
std::ostream& write_with_file_o(std::ostream&);

std::ostream& operator<<(std::ostream& os, Obj const& obj) {
  if (&os == &std::cout) {
    return write_with_console_o(os);
  }
  return write_with_file_o(os);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接