【问题标题】:C++: Unwanted Conversions between ostream and ofstreamC++:ostream 和 ofstream 之间不需要的转换
【发布时间】:2018-10-24 19:09:59
【问题描述】:

我一直在开发一个个人词典应用程序,它可以帮助您记住所学的单词。它是通过 CLI 操作的(不要质疑这一点,这只是一个测试,我对 CLI 应用程序有一种奇怪的热情)。所以,我当然使用ostreams 在 CLI 上编写信息。我习惯为每个类编写operator<< 重载(用于ostreams),这样我就可以建立一个多级输出系统(基本上每个对象都可以为自己“说话”)。

为了持久化一个字典对象,我想使用ofstream 并用它写一个文件。当然,我也为ofstream 编写了operator<< 重载,并采用相同的“分层”结构。

因此,我现在在每个类中都有两个 operator<< 重载,例如“Dictionary”:

ostream& operator<<(ostream&, const Dictionary&);
ofstream& operator<<(ofstream&, const Dictionary&);

(这只是头文件中的声明)

请注意,这两个重载不同的事情非常重要。我不想在 CLI 上有一些奇怪的面向持久性的特殊格式文本而且我的文件中也不是用户友好的纯文本。

问题在于,由于ostreamofstream 的继承结构,ofstream 有时会隐式转换为ostream。当这种情况发生在我的 file 输出操作堆栈中间时,程序会突然跳入错误的重载并在文件中打印纯文本。

我的问题很简单:有没有办法避免或恢复这些不需要的隐式转换,以便让我的程序跳转到正确的重载?或者有没有其他好的方法来解决这个问题?

编辑 1

有人在 cmets 中指出,这不是隐含的转换。 ofstream 有时被“视为”它的基类 ostream。问题是在某些时候对象“忘记”它是ofstream 并丢失所有与文件相关的信息。从那里开始,它只是一个ostream,这就是我所说的“转换”。

编辑 2:

可以在此处找到程序中发生“不需要的转换”的确切点:

ofstream& operator<<(ofstream& of, const Section& s) {
    return s.print_ofstream(of);
}

所以这个运算符重载调用“print_ofstream”:

ofstream& Section::print_ofstream(ofstream& of) const {
    of << "sec" << Util::ID_TO_STRING(section_id) << ":\n";
    for (pair<Wordlist, Wordlist> pwl : translations) {
        of << '{' << pwl.first << '=' << pwl.second << "}\n";
    }
    of << "#\n";
    return of;
}

注意“pwl”是一对两个Wordlists,因此pwl.first / pwl.second 是Wordlist。因此,通常of &lt;&lt; '{' &lt;&lt; pwl.first &lt;&lt; '=' &lt;&lt; pwl.second &lt;&lt; "}\n"; 行应该调用Wordlist 中的ofstream operator&lt;&lt; 重载。但事实并非如此。而是调用另一个重载方法:

ostream& operator<<(ostream& o, const Wordlist& wl) {
    return wl.print_ostream(o);
}

【问题讨论】:

  • 不是ofstream被隐式转换,而是ostreamofstream基类
  • 确实如此,但我有点困惑,返回类型为ofstream的方法可以返回ostream。我会反过来理解它......
  • 你能显示有问题的代码吗?
  • @JETM 当然是的。现在有一个“EDIT 2”提供此信息

标签: c++ file stream persistence overloading


【解决方案1】:

您仅将流式传输所需的特定operator&lt;&lt; DictionarySectionWordlist 等对象重载到std::ofstream,但std::ofstream 继承许多其他@ 987654327@s 来自std::ostream,这些运算符都将ostream&amp; 作为输入并返回ostream&amp; 作为输出。因此,例如,of &lt;&lt; "sec" 将返回 ostream&amp;,即使 ofstd::ofstream,然后 ostream&amp; 将用于后续的 &lt;&lt; 调用,直到到达 ;。这些是您正在经历的“隐式转换”。

真正的问题是,为什么要 operator&lt;&lt; 根据写入的 std::ostream 的类型输出不同的数据?这违背了 C++ 的流模型。如果您真的想要,您必须将print_ofstream(ofstream&amp;) 更改为print_ostream(ostream&amp;),然后使用dynamic_cast 动态检测实际的std::ostream 派生类型。与Wordlist 以及任何其他需要它的类相同。

一个更简单、更安全的选择是在你的类中存储一个标志来控制它们的数据应该如何输出,而不管使用的std::ostream是什么类型。然后您可以根据需要设置该标志。甚至可以定义一些辅助 I/O 操纵器来设置这些标志,同时进行 &lt;&lt; 调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 2011-03-20
    相关资源
    最近更新 更多