输入输出流,看似复杂却更好用----小话c++(2) (三)

2014-11-24 12:01:29 · 作者: · 浏览: 4
会出现这种情况?

A: 出现这个问题的原因主要在于c++使用类的概念,而且输入输出牵扯到较多的类继承体系,每个类都可能有一些可以被调用的公共函数或者可使用的公共变量,导致最终使用子类进行操作的时候,同样可以使用基类的公共函数得到一些信息,这个可能导致可以操作输入输出流的方式极大增加。但是,不管有多少变形的方式,基本功能依然是那些:输入,输出,查询流状态,设置流参数和刷新。总而言之,不管你想封装多少函数,c++不会阻止你,不过链接器可能阻止最终的可执行文件的生成(如果最终的可执行文件超过系统限制).

Q: 对于cout, 形如cout << endl 这种形式为什么可以通过编译?

A: 这种形式和cout << boolalpha也是类似的。形如如下代码:

[cpp] #include

using namespace std;

int main (int argc, const char * argv[])
{
bool b = true;
cout << boolalpha << b << endl;
return 0;
}
#include

using namespace std;

int main (int argc, const char * argv[])
{
bool b = true;
cout << boolalpha << b << endl;
return 0;
}根据重载运算符,如下代码亦是可以的:
[cpp] #include

using namespace std;

int main (int argc, const char * argv[])
{
bool b = true;
cout.operator<<(boolalpha).operator<<(b).operator<<(endl);
return 0;
}
#include

using namespace std;

int main (int argc, const char * argv[])
{
bool b = true;
cout.operator<<(boolalpha).operator<<(b).operator<<(endl);
return 0;
}那么boolalpha和endl到底是什么呢?
查看endl的声明和定义,发现如下,在basic_ostream类中:

[cpp] template
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{ return flush(__os.put(__os.widen('\n'))); }
template
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{ return flush(__os.put(__os.widen('\n'))); }boolalpha的声明和定义,如下在ios_base类中:
[cpp] inline ios_base&
boolalpha(ios_base& __base)
{
__base.setf(ios_base::boolalpha);
return __base;
}
inline ios_base&
boolalpha(ios_base& __base)
{
__base.setf(ios_base::boolalpha);
return __base;
}既然如此,如下的代码就应该可以运行:
[cpp] #include

using namespace std;

int main (int argc, const char * argv[])
{
bool b = true;

boolalpha(cout);
cout << b;
endl(cout);

return 0;
}
#include

using namespace std;

int main (int argc, const char * argv[])
{
bool b = true;

boolalpha(cout);
cout << b;
endl(cout);

return 0;
}运行,和上面代码效果一致。从上可以看出,boolalpha和endl是函数,它们的原型分别为:
[cpp] inline ios_base&
boolalpha(ios_base& __base);
inline ios_base&
boolalpha(ios_base& __base);[cpp] template
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os);
template
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os);
从basic_ostream类中可以找到如下函数:[cpp] __ostream_type&
operator<<(__ostream_type& (*__pf)(__ostream_type&))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 60. What is a formatted input function
// The inserters for manipulators are *not* formatted output functions.
return __pf(*this);
}

__ostream_type&
operator<<(ios_base& (*__pf) (ios_base&))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 60. What is a formatted input function
// The inserters for manipulators are *not* formatted output functions.
__pf(*this);
return *this;
}

typedef basic_ostream<_CharT, _Traits> __ostream_type;
__ostream_type&
operator<<(__ostream_type& (*__pf)(__ostream_type&))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 60. What is a formatted input function
// The inserters for manipulators are *not* formatted output functions.
return __pf(*this);
}

__ostream_type&
operator<<(ios_base& (*__pf) (ios_base&))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 60. What is a formatted input function
// The inserters for manipulators are *not* formatted output functions.
__pf(*this);
return *this;
}

typedef basic_ostream<_CharT, _Traits> __ostream_type;



这样就简单了,cout.operator<<(boolalpha)实际上是调用了cout的operator<<(ios_base &(*__pf)(ios_base &))函数,而cout.operator<<(endl)实际上是调用了cout的operator<<(__ostream_type &(*__pf)(__ostream_type &))函数。boolalpha和endl只不过是被当做函数指针传入当参数而已。内部将分别调用boolalpha(cout);和endl(cout);来实现最终功能。我觉得这么设计,其一好处无非是让使用者更分便, 到处使用<<即可,不用想着到底是重载哪个函数,内部已经为上层做好了转换。同时,对于操作子,最终不是cout在操作它,而是操作子在操作cout.


Q: cout << "\n";到底会不会刷新缓冲区?

A: 对于行缓冲来说,它当然会刷新缓冲区。千万不要认为只有cout << endl;才会强制刷新缓冲区。如下代码,

[cpp] #include

using namespace std;

int main (int argc, const char * argv[])
{
cout << "hello";
cout << "ok\n";
cout << endl;
cout << "thanks";

return 0;
}
#include

using namespace std;

int main (int argc, const char * argv[])
{
cout << "hello";
cout << "ok\n";
cout << endl;
cout << "thanks";

retur