如何覆盖ostream<<已定义类型的运算符 [英] How to override ostream << operator for already defined type
问题描述
我目前正在使用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
的重载, float
和std::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<<已定义类型的运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!