如何覆盖已定义类型的 ostream <<运算符 如何使下拉子菜单直接显示在其父菜单下方<li>?

How to override ostream << operator for already defined type

本文关键字:lt 菜单 显示 li gt 运算符 覆盖 何覆盖 定义 何使下 ostream      更新时间:2023-10-16

我目前正在开发一个现有库的端口,该库使用ostream写入终端。

ostream是作为端口的一部分派生的。

所使用的ostream派生类定义如下:

class owstream: public std::ostream {
public:
    CTerminal * output;
    giac::context * contextptr;
    owstream(CTerminal *, giac::context * contextptr , int = 0);
    virtual ~owstream();
};

用于输出一些数据,通常是整数和双精度。

问题是我正在工作的平台有一个错误的双打印例程,导致内核崩溃。

在某些情况下,如果我这样做:

ostream* mystream = new ostream(...);
(*mystream) << 1.23456

大爆炸》

所以,我试图重写<<特定类型的操作符,如:

ostream* GetStream() { return = new MyOStream(...); }
....
ostream* mystream = GetStream()
mystream << 1.23456;

不幸的是,操作符<

我试着把它扩展成这样:

class owstream: public std::ostream {
    friend std::ostream& operator<<(std::ostream& out, double val);
  public:
    CTerminal * output;
    giac::context * contextptr;
    owstream(CTerminal *, giac::context * contextptr , int = 0);
    virtual ~owstream();
};
extern std::ostream& operator<<(std::ostream &out, double val);

但是这会导致关于操作符<<具有二义性,因为很明显这是一种已经被iostream基类处理过的类型。

我开始怀疑这是否可能。

如何实现<<当给定一个特定的、已经处理的类型时,重写行为的操作符?

目标是能够做一些事情,如:

cout << 1.234567

不崩溃(我显然不会使用cout,但是上面定义的GetStream()可以很好地返回cout)

我看到你目前的方法/实施有三个问题。

问题# 1

即使您成功地让它使用std::ostream作为第一个参数并返回值,它也不会正确工作。问题主要是由于超载的operator<<返回一个ostream。在第一个值被发送到owstream之后,所有后续的值都被发送到返回的ostream。这会让你回到最初问题的起点。为了使其正常工作,您需要将owstream作为第一个参数,并在重载的operator<<中返回owstream

问题# 2

另一个问题是owstream可以隐式转换为std::ostream。根据owstream在项目中的使用方式,在某些情况下,您提供的重载可能不会产生影响。例如,如果将owstream类型的对象传递给接受std::ostream类型的函数,则可能会遇到当前遇到的问题。您可以通过使用private继承来防止这种情况的发生。这将防止将owstream隐式地用作std::ostream。使用private继承还有一个好处,它可以防止您在不知情的情况下使用std::ostream中的函数,这可能会导致您回到最初的问题。对于绝对需要std::ostream的实例,您可以使用访问器函数显式地检索对它的引用。

问题# 3

最后一个问题是std::ostream包含operator<<的重载,该重载处理std::ostream特定的IO操纵符,如std::endl。如果你没有提供一个重载来专门处理这些,那么std::ostream中的重载就会被使用,你又回到了开始的地方。如果使用上面描述的private继承,并且不提供重载来处理操纵符,则编译失败。


<

解决方案/strong>

下面的解决方案类似于JRG提供的解决方案,包括doublefloatstd::ostream IO操纵符的访问器函数和重载。这是一个完整的工作示例,为了简单起见,它使用了std::cout中的流缓冲区。我包含了float的重载,因为有缺陷的库实现可能与它们有类似的问题。它还使用私有继承来防止对std::ostream的隐式转换。

我在vc++ 10和GCC 4.7.2上测试了它。您可能需要根据编译器和库的兼容性进行一些调整。

#include <ostream>
#include <iostream>
#include <sstream>
class owstream : private std::ostream
{
public:
    owstream(std::streambuf* sb)
        : std::ostream(sb)
    {}
    // Template based operator...ohhhhhh ahhhhh.
    template <typename T>
    friend owstream& operator<<(owstream&, const T&);
    // Additional overload to handle ostream specific io manipulators 
    friend owstream& operator<<(owstream&, std::ostream& (*)(std::ostream&));
    // Accessor function to get a reference to the ostream
    std::ostream& get_ostream() { return *this; }
};

template <typename T>
inline owstream&
operator<<(owstream& out, const T& value)
{
    static_cast<std::ostream&>(out) << value;
    return out;
}
//  overload for double
template <>
inline owstream&
operator<<(owstream& out, const double& value)
{
    std::stringstream ss;
    ss << value;
    return out << ss.str();
}
//  overload for float
template <>
inline owstream&
operator<<(owstream& out, const float& value)
{
    std::stringstream ss;
    ss << value;
    return out << ss.str();
}
//  overload for std::ostream specific io manipulators
inline owstream&
operator<<(owstream& out, std::ostream& (*func)(std::ostream&))
{
    static_cast<std::ostream&>(out) << func;
    return out;
}
int main()
{
    owstream ows(std::cout.rdbuf());
    ows << std::endl;
    ows << "hello " << 1.0 << " " << 2.0f << std::endl;
}

这样怎么样:

template <typename T>
owstream& operator<<(owstream&, const T&);
template <typename T>
inline owstream&
operator<<(owstream& os, const T& val)
{
   std::ostream& stdos = static_cast<std::ostream&>(os);
   stdos << val;
   return os;
}
template <>
inline owstream&
operator<<(owstream& os, const double& val)
{
   std::stringstream ss;
   ss << val;
   os << ss.str();
   return os;
}