自定义流操作符的问题

nde123456 2009-04-16 12:00:31
自定义一个字符串流的类mystream
class mystream : public stringstream
{
private:
string str;
};

想要为mystream自定义一个流操作符myend
mystream mystr;
mystr << 5 << "abc" << 3.57 << myend;
想在收到流操作符myend时执行str=mystr.str();

请教高手怎么写这个代码?

...全文
263 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
nde123456 2009-04-16
  • 打赏
  • 举报
回复
正如楼上所说:定义了mystream自己的某种类型流运算符后,将导致继承的ostream的流运算符被隐藏

不太理解的是,mystream只定义一个<<(mystream&),为什么继承下来的ostream的<<(int &)被屏蔽了?
  • 打赏
  • 举报
回复
[Quote=引用楼主 nde123456 的帖子:]
自定义一个字符串流的类mystream
class mystream : public stringstream
{
private:
string str;
};

想要为mystream自定义一个流操作符myend
mystream mystr;
mystr < < 5 < < "abc" < < 3.57 < < myend;
想在收到流操作符myend时执行str=mystr.str();

请教高手怎么写这个代码?
[/Quote]

在mystream重载<<操作符啊
beyond071 2009-04-16
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 nde123456 的回复:]
我想要支持完整的流格式化功能,如果不继承stringstream,mystream是不是得把ostream支持的所有 < <全部实现一遍?

继承的方法可以省掉这些工作,但是自定义的操作符加不进去
[/Quote]


mystream& mystream::operator<<(mystream& (__cdecl *_Pfn)(mystream&))
{
assert(NULL != _Pfn);
return (*_Pfn)(*this);
}
mystream& myend(mystream& ms)
{
ms._str = ms.str();
return ms;
}
code]
当定义了mystream自己的某种类型流运算符后,将导致继承的ostream的流运算符被隐藏!(因为stringstream中没有虚函数)。
因此,即使继承stringstream也得对<<支持的各类型进行重写。

如果想继续强制使用派生类来完成功能,那么可以对派生类的基类成分使用ostream的<<,操作如下。
[code=C/C++]
mystream mystr;
//取出基类成分
stringstream *os = &mystr;
//由于stringstream中的<<都不是虚函数,他们静态绑定在os对象,对*os的操作都是标准的ostream operator <<
*os << 5 << "abc" << 3.57;
//对mystream对象使用myend
mystr << myend;
cout << mystr<<endl;


或者直接用dynamic_cast取基类成分

mystream mystr;
//取出基类成分
dynamic_cast<stringstream>(mystr) << 5 << "abc" << 3.57;
//对mystream对象使用myend
mystr << myend;
cout << mystr<<endl;


总而言之,这样的继承使用起来是相当的不方便!而且不好理解。这主要是由于继承的类不提供虚函数的缘故...
建议这样的stringstream的继承,如果要加入自己的流操作,就必须自己重写所有支持的运算符。
或者就如3楼所做的,干脆就不把它作为继承,只是把streamstring对象作为一个成员封在mystream里(Layering),
重写所要支持的类型的operator <<,这样便于理解,也很稳健。

hityct1 2009-04-16
  • 打赏
  • 举报
回复
str=mystr.str();
啥意思?

myend的编写可参考endl。
jiemengw 2009-04-16
  • 打赏
  • 举报
回复
很好啊,借用了楼上几位的代码,改变了几个小程序!呵呵,新手请各位大侠多多指点啊!
nde123456 2009-04-16
  • 打赏
  • 举报
回复
我想要支持完整的流格式化功能,如果不继承stringstream,mystream是不是得把ostream支持的所有<<全部实现一遍?

继承的方法可以省掉这些工作,但是自定义的操作符加不进去
beyond071 2009-04-16
  • 打赏
  • 举报
回复
sorry 没看清楚,原来已经声明了友元啊!
beyond071 2009-04-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 nde123456 的回复:]
感谢hityct1
VC6下编译出2个问题
1. os < <ms._str;
cannot access private member declared in class 'mystream'
2. cout < < mystr < <endl;
'operator < <' is ambiguous
[/Quote]
ostream& operator <<(ostream& os, const mystream& ms)
需要访问mystream的私有成员,因此它需要声明为mystream的友元函数。在mystream的public中添加
friend ostream& operator <<(ostream&, const mystream&);
nde123456 2009-04-16
  • 打赏
  • 举报
回复
感谢hityct1
VC6下编译出2个问题
1. os<<ms._str;
cannot access private member declared in class 'mystream'
2. cout << mystr<<endl;
'operator <<' is ambiguous


hityct1 2009-04-16
  • 打赏
  • 举报
回复
不采用继承方式。

#include <iostream>
#include <sstream>
#include <cassert>

using namespace std;

class mystream
{
private:
stringstream _ss;
string _str;
public:
friend mystream& myend(mystream& ms);
friend ostream& operator <<(ostream& os, const mystream& ms);
public:
mystream& operator<< (const int& val )
{
_ss <<val;
return *this;
}

mystream& operator<< (const char* s )
{
_ss <<s;
return *this;
}

mystream& operator<< (const double& val )
{
_ss <<val;
return *this;
}

mystream& operator<<(mystream& ( __cdecl *fun)(mystream&) );
};

mystream& myend(mystream& ms)
{
ms._str = ms._ss.str();

return ms;
}

ostream& operator <<(ostream& os, const mystream& ms)
{
os<<ms._str;
return os;
}

mystream& mystream::operator<<(mystream& (*fun)(mystream&) )
{
assert(NULL != fun);
return ((*fun)(*this));
}

int main()
{
mystream mystr;

mystr << 5<< "abc" << 3.57<< myend;
cout << mystr<<endl;

return 0;
}
beyond071 2009-04-16
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 nde123456 的回复:]
正如楼上所说:定义了mystream自己的某种类型流运算符后,将导致继承的ostream的流运算符被隐藏

不太理解的是,mystream只定义一个 < <(mystream&),为什么继承下来的ostream的 < <(int &)被屏蔽了?
[/Quote]

楼主,并不只是继承下来的ostream的 <<(int &)被屏蔽了,是所有类型继承下来的operator <<都被屏蔽了!
为什么会只提示int上有二义性呢?

原因是operator <<的返回值是ostream&的引用,所以后面跟着的char*,double类型都没有继续报错了。
如果你把输入的顺序换换,那么你可以看到,它们其实都被屏蔽了。

另外,为什么说所有类型的operator<<都要被重载呢?
如果继续使用继承而来的ostream& operator << (),那么返回的都是基类对象,那么连续使用operator <<,
实际都操作的是mystream的基类成分!但最后如果想用myend来结尾,将会发现没法调用我们定义的:

mystream& mystream::operator<<(mystream& (__cdecl *_Pfn)(mystream&))

而会去调用:
ostream& operator << (ostream& (__cdecl *_Pfn)(mystream&))

这是因为前面一个operator <<返回的是基类成分!只能调用基类的operator <<,这样执行下来的后果是
把myend函数的指针地址给塞进了stringstream,完全不是我们想要的。

这个时候想结尾,只能把以前的代码拆开了...

mystr<< 5.6 << 5<< "abc" << 3.57;
mystr << myend; //可以正确调用myend啦

注:上面这段代码要编译过,首先得实现mystream对int类型的支持!

mystream& operator<<(int __w64 _Val){
dynamic_cast<stringstream&>(*this) << _Val;
return *this;//返回的是基类成分!所以后面的<<可以工作了
}

可这样一来本来很方便的流操作变得很别扭,而且没人能保证一开始一定输入的是int型数据呀!
最后,还得一条一条的实现对mystream& operator <<()各类型的支持^_^
aaaa3105563 2009-04-16
  • 打赏
  • 举报
回复
学习·

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧