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

杜智超*_*杜智超 0 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;
}
Run Code Online (Sandbox Code Playgroud)

并输出:

0x401b90

你好,世界!

编译器信息:

g ++(GCC)4.8.5 20150623(Red Hat 4.8.5-11)

在我看来,(a)std :: stringstream的str()方法返回一个字符串.(b)std :: cout是std :: ostream的对象.因此,两个测试都将调用ostream的相同运算符函数并打印相同的"Hello world".但测试1打印一个地址,测试2打印正确的"Hello world".
我怎么了 ?谢谢.

Que*_*tin 6

ss << "Hello World!";解决了对以下重载的调用(本页#2):

template <class Traits>
std::basic_ostream<char, Traits> &std::operator << (
    std::basic_ostream<char, Traits> &os, char const *s
);
Run Code Online (Sandbox Code Playgroud)

此重载将字符串文字衰减为a char const *,然后将其打印出来.

为了搅拌泥浆,我们可以尝试以下代码段:

TestLog tl;
tl << "Hello World!";
Run Code Online (Sandbox Code Playgroud)

这个将解决上面的重载,并打印Hello World!.那是因为tl是一个左值,它可以绑定到非const左值引用的第一个参数.

在你的例子中,TestLog()是一个右值 - 这个过载无法匹配!因此,选择另一个重载(这里#7):

std::basic_ostream &std::basic_ostream::operator << (void const *value);
Run Code Online (Sandbox Code Playgroud)

这一个是成员函数重载,并且已经继承自std::stringstream.即使您无法将非const引用绑定到右值,也可以const在右值上调用非成员函数.所以这个重载是一个有效的匹配,并且它被选中 - 打印文字的地址就好像它是任何旧指针一样.

C++ 11为解决这个问题带来了新的重载,在#3处可见:

template <class CharT, class Traits, class T>
std::basic_ostream<CharT, Traits> &operator << (
    basic_ostream<CharT, Traits> &&os, T const &value
);
Run Code Online (Sandbox Code Playgroud)

T const &char const[N]完全匹配文字的类型,因此排名高于void const *重载.作为第一个参数的rvalue引用绑定到临时就好了.

命名的右值引用被认为os << value;是左值,因此该函数可以再次调用trampoline返回到左值流的重载集.因此,在C++ 11及更高版本中,两行都打印出来Hello World!.