cout一个字符串流但打印一个指针

时间:2017-01-02 10:47:14

标签: c++ c++03

这是我的代码:

#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; 我怎么了 ?感谢。

1 个答案:

答案 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!