如何覆盖ostream<<已定义类型的运算符 [英] How to override ostream << operator for already defined type

查看:85
本文介绍了如何覆盖ostream<<已定义类型的运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用ostream来写入终端的现有库的端口上.

I'm currently working on a port of an existing library which makes use of ostream to write to a terminal.

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

The ostream was derived as part of the port.

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

The ostream derivative class used is defined as so:

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

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

This is used to output some data, typically integers and doubles.

问题是我正在使用的平台具有错误的双重打印例程,导致内核崩溃.

The problem is that the platform I'm working on has a buggy double print routine that causes kernel crash.

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

So in some cases, if I do:

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

kaboom

因此,我尝试覆盖<<特定类型的运算符,如下所示:

so, I tried to override the << operator for certain type, like so:

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

....

ostream* mystream = GetStream()
mystream << 1.23456;

不幸的是,操作员<< ostream中的成员不是虚拟的,因此如果我创建了重写的运算符<<成员将永远不会被召唤.

Unfortunately, the operator<< member in ostream isn't virtual so if I created an overridden operator<< member would never be called.

我尝试用以下方式扩展它:

I tried to extend it with something like:

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基类已经处理过的类型.

But this causes compilation error in regards to operator << being ambiguous, as obviously this is a type already handle by the base iostream class.

我开始怀疑这是否完全可能.

I'm starting to wonder if this is at all possible.

您将如何实现<<给定特定的已处理类型时,运算符将覆盖行为?

How would you implement the << operator to override the behaviour when given a particular, already handled type ?

目标是能够执行以下操作:

The aim being able to do something like:

cout << 1.234567

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

not crashing (I obviously wouldn't be using cout, but GetStream() as defined above, could very well return cout)

推荐答案

我发现您当前的方法/实现存在三个问题.

I see three problems with your current approach/implementation.

问题1

即使您成功使用std::ostream作为第一个参数并返回值,也无法正常工作.问题主要源于从重载的operator<<返回ostream.在第一个值发送到owstream之后,所有后续值都将发送到返回的ostream.这使您回到最初的问题的起点.为了使其正常工作,您需要将owstream作为第一个参数,并在重载的operator<<中返回owstream.

Even if you were to successfully get it to use std::ostream as the first parameter and return value it would not work correctly. The problem stems mainly from returning an ostream from the overloaded operator<<. After the first value has been sent to the owstream all subsequent values get sent to the returned ostream. This puts you right back where you started with the original problem. In order to for this to work properly you need to take owstream as the first parameter and return an owstream in the overloaded operator<<.

问题2

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

Another problem is owstream is implicitly convertible to std::ostream. Depending on how owstream is used in your project there is a possibility that the overloads you provide may not make a difference in certain situations. For instance if an object of type owstream is passed to a function that accepts a std::ostream you may end up encountering the problem you are currently experiencing. You can prevent this from happening by using private inheritance. This will prevent any implicit use of owstream as a std::ostream. Using private inheritance also has the benefit of preventing you from unknowingly using functions in std::ostream which may lead you back to your original problem. For instances where a std::ostream is absolutely necessary you can use an accessor function to explicitly retrieve a reference to it.

问题3

最后一个问题是std::ostream包含operator<<的重载,该重载可处理std::ostream特定的IO机械手,例如std::endl.如果您没有提供过载来专门处理这些过载,则会使用std::ostream中的过载,并且您再次回到刚开始的位置.如果您使用上述的private继承,并且未提供重载来处理操纵器,则它将无法编译.

The last issue is that std::ostream includes an overload of operator<< that handles std::ostream specific IO manipulators such as std::endl. If you do not provide an overload to specifically handle these the one in std::ostream gets used and once again you end up right back where you started. If you use private inheritance described above and do not provide an overload to handle the manipulators it will fail to compile.

解决方案

以下解决方案类似于 JRG 提供的解决方案,其中包括访问器功能和double的重载, floatstd::ostream IO机械手.这是一个完整的工作示例,为简单起见,使用了std::cout中的流缓冲区.我包括了float的重载,因为缺乏库的实现可能与它们有类似的问题.它还使用私有继承来防止隐式转换为std::ostream.

The solution below is similar to the one provided by JRG and includes the accessor function and overloads for double, float, and std::ostream IO manipulators. It is a complete working example and uses the stream buffer from std::cout for simplicity. I included the overload for float as the deficient library implementation may a similar issue with them. It also uses private inheritance to prevent implicit conversions to std::ostream.

我在VC ++ 10和GCC 4.7.2上进行了测试.您可能需要进行一些调整,具体取决于编译器和库的兼容性.

I tested it on VC++10 and GCC 4.7.2. You may need to make some adjustments depending on how compliant your compiler and libraries are.

#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;
}

这篇关于如何覆盖ostream&lt;&lt;已定义类型的运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆