这是我的代码:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class TestLog: public std::stringstream
{
public:
~TestLog()
{
cout << (str()) << endl; // Why does this print an address ?
}
};
int main()
{
TestLog() << "Hello World!"; //test 1 print an address
stringstream ss;
ss << "Hello World!";
cout << (ss.str()) << endl; //test 2 print a string
return 0;
}
输出:
0x401b90
Hello World!
编译器信息:
g ++(GCC)4.8.5 20150623(Red Hat 4.8.5-11)
在我看来, (a)std :: stringstream的str()方法返回一个字符串。 (b)std :: cout是std :: ostream的对象。 因此,两个测试中的两个都将调用ostream的相同运算符函数并打印相同的&#34; Hello world&#34;。 但是测试1打印一个地址,测试2打印正确的&#34; Hello world&#34; 我怎么了 ?感谢。
答案 0 :(得分:6)
ss << "Hello World!";
解析为调用以下重载(#2 on this page):
template <class Traits>
std::basic_ostream<char, Traits> &std::operator << (
std::basic_ostream<char, Traits> &os, char const *s
);
此重载会将字符串文字衰减为char const *
,然后将其打印出来。
为了搅拌泥浆,我们可以尝试以下代码段:
TestLog tl;
tl << "Hello World!";
这个也将解析为上面的重载,然后打印Hello World!
。这是因为tl
是一个左值,可以绑定到非const
左值参考的第一个参数。
在您的示例中,TestLog()
是右值 - 此过载无法匹配!因此,选择另一个重载(#7 here):
std::basic_ostream &std::basic_ostream::operator << (void const *value);
这是一个成员函数重载,并且已从std::stringstream
继承。即使您无法将非const
引用绑定到右值,您也可以在右值上调用非const
成员函数。所以这个重载是一个有效的匹配,并且它被选中 - 打印文字的地址,好像它是任何旧指针一样。
C ++ 11为解决此问题带来了新的重载,可见#3 here:
template <class CharT, class Traits, class T>
std::basic_ostream<CharT, Traits> &operator << (
basic_ostream<CharT, Traits> &&os, T const &value
);
T const &
完全匹配文字的char const[N]
类型,因此排名高于void const *
重载。作为第一个参数的rvalue引用绑定到临时就好了。
命名的右值引用被认为是左值,因此该函数可以再次调用os << value;
以蹦床返回到左值流的重载集。因此,在C ++ 11及更高版本中,两行都打印Hello World!
。