как работает cout <<? - PullRequest
       10

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

44 голосов
/ 01 апреля 2011

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

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

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

Кто-нибудь здесь знает? Спасибо

1 Ответ

46 голосов
/ 01 апреля 2011

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

Это «особенный» в том смысле, что он ссылается на консоль, но в остальном он ведет себя точно так же, как ofstreamили ostringstream.

РЕДАКТИРОВАТЬ : Цепочка работает так же, как и для любых других операторов.Рассмотрим:

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 работает по той же причине, что и << s на вершине 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;

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

...