Подтвердить что ты не робот

Как работает cout <<?

Мне было интересно, как std::cout может использовать <<, как и он.

Мое главное недоумение заключается в том, std::cout как экземпляр чего-то. В принципе, как определяется <<? Если я делаю это для пользовательского класса, мне нужен экземпляр какого-то типа...

Я мог бы реализовать его как своего рода хак с указателями void или что-то в этом роде, но я хотел бы видеть, как это делается.

Кто-нибудь знает? Благодаря

4b9b3361

Ответ 1

std::cout является экземпляром std::ostream. std::cout << "something" вызывает одну из перегрузок operator<<, как это было бы сделано для любого экземпляра std::ostream.

Он "особый" в том, что он ссылается на консоль, но в противном случае он ведет себя точно так же, как ofstream или ostringstream.

EDIT: цепочка работает так же, как и для любых других операторов. Рассмотрим:

class MyType
{
    friend std::ostream& operator<<(std::ostream& target, const MyType& source);
    int val;
public:
    MyType()
        : val(0)
    { }
    MyType& Add(int toAdd)
    {
        val += toAdd;
        return *this;
    }
};

MyType& operator+(MyType& target, int toAdd)
{
    return target.Add(toAdd);
}

std::ostream& operator<<(std::ostream& target, const MyType& source)
{
    target << source.val;
    return target; //Make chaining work
}

int main()
{
    MyType value1;
    value1 + 2 + 3 + 4;
    std::cout << value1 << " and done!" << std::endl;
}

В этом случае цепочка для + s на MyType работает по той же причине, что << работает поверх std::ostream. Оба + и << являются лево-ассоциативными, что означает, что они оцениваются слева направо. В случае перегруженных операторов оператор заменяется эквивалентным вызовом функции.

EDIT2: немного подробнее:

Скажем, вы компилятор, и вы разбираете

std::cout << value1 << " and done!" << std::endl;

Во-первых, << остается ассоциативным, поэтому вы начинаете с левой стороны. Вы оцениваете первый << и включаете его в вызов функции:

operator<<(std::cout, value1) << " and done!" << std::endl;

Затем вы увидите, что у вас снова есть std::ostream (результат вызова operator<<) и char *, который вы снова включаете в вызов функции:

operator<<(operator<<(std::cout, value1)," and done!") << std::endl;

et cetera, пока вы не обработали весь оператор.