'друг' функционирует и <<перегрузка оператора: Что надлежащий путь состоит в том, чтобы перегрузить оператор для класса?

В проекте я продолжаю работать, у меня есть a Score класс, определенный ниже в score.h. Я пытаюсь перегрузить его так, когда a << операция выполняется на нем, _points + " " + _name печатается.

Вот то, что я пытался сделать:

ostream & Score::operator<< (ostream & os, Score right)
{
    os << right.getPoints() << " " << right.scoreGetName();
    return os;
}

Вот возвращенные ошибки:

score.h(30) : error C2804: binary 'operator <<' has too many parameters

(Эта ошибка появляется 4 раза, на самом деле),

Мне удалось получить его работающий путем объявления перегрузки как другу функция:

friend ostream & operator<< (ostream & os, Score right);

И удаление Score:: из объявления функции в score.cpp (эффективно не объявление его как участник).

Почему это работает, уже бывшая часть кода не делает?

Спасибо за внимание!

Править

Я удалил все упоминания перегрузке на заголовочном файле... все же я получаю следующее (и только) ошибка. binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion) Каким образом мой тест, в основном (), не может найти соответствующую перегрузку? (это не включение, я проверил),

Ниже полный score.h

#ifndef SCORE_H_
#define SCORE_H_

#include <string>
#include <iostream>
#include <iostream>

using std::string;
using std::ostream;

class Score
{

public:
    Score(string name);
    Score();
    virtual ~Score();
    void addPoints(int n);
    string scoreGetName() const;
    int getPoints() const;
    void scoreSetName(string name);
    bool operator>(const Score right) const;

private:
    string _name;
    int _points;

};
#endif
22
задан F. P. 25 July 2016 в 15:45
поделиться

3 ответа

Примечание: Вы можете посмотреть FAQ по перегрузке оператора .


Бинарные операторы могут быть либо членами класса их левого аргумента, либо свободными функциями. (Некоторые операторы, такие как присваивание, должны быть членами.) Поскольку левый аргумент операторов потока является потоком, операторы потока либо должны быть членами класса потока, либо свободными функциями. Канонический способ реализации operator << для любого типа следующий:

std::ostream& operator<<(std::ostream& os, const T& obj)
{
   // stream obj's data into os
   return os;
}

Обратите внимание, что это не функция-член. Также обратите внимание, что для потоковой передачи объекта требуется ссылка const . Это потому, что вы не хотите копировать объект для его потоковой передачи, и вы также не хотите, чтобы поток изменял его.


Иногда вы хотите передать в поток объекты, внутреннее устройство которых недоступно через открытый интерфейс их класса, поэтому оператор не может получить к ним доступ. Тогда у вас есть два варианта: либо поместить открытый член в класс, который выполняет потоковую передачу

class T {
  public:
    void stream_to(std::ostream&) const {os << obj.data_;}
  private:
    int data_;
};

, и вызвать его из оператора:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   obj.stream_to(os);
   return os;
}

, либо сделать оператор другом

class T {
  public:
    friend std::ostream& operator<<(std::ostream&, const T&);
  private:
    int data_;
};

, чтобы он мог получить доступ к классу 'личные части:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   os << obj.data_;
   return os;
}
61
ответ дан 29 November 2019 в 03:31
поделиться

Допустим, вы хотите написать перегрузку оператора для + , чтобы можно было добавить два объекта Score к каждому другой и еще один, чтобы вы могли добавить int к Score , и третий, чтобы вы могли добавить Score к int . Те, у которых Score является первым параметром, могут быть функциями-членами Score. Но тот, в котором первым параметром является int , не может стать функцией-членом int , верно? Чтобы помочь вам в этом, вам разрешено писать их как бесплатные функции. Вот что происходит с этим оператором << , вы не можете добавить функцию-член в ostream , поэтому вы пишете бесплатную функцию. Вот что значит убрать часть Score :: .

Итак, почему это должен быть друг ? Это не так. Вы вызываете только общедоступные методы ( getPoints и scoreGetName ). Вы видите множество дружественных операторов, потому что им нравится напрямую обращаться к приватным переменным. Для меня это нормально, потому что они написаны и поддерживаются человеком, ведущим класс. Только не путайте дружескую часть с частью функции-члена против свободной функции.

9
ответ дан 29 November 2019 в 03:31
поделиться

Вы получаете ошибки компиляции, когда operator<< является функцией-членом в примере, потому что вы создаете operator<<, который принимает Score в качестве первого параметра (объект, на котором вызывается метод), а затем дает ему дополнительный параметр в конце.

Когда вы вызываете бинарный оператор, объявленный как функция-член, левая часть выражения - это объект, на котором вызывается метод. Например, a + b может работать так:

A a;
B b

a.operator+(b)

Обычно предпочтительнее использовать нечленные бинарные операторы (а в некоторых случаях -- например, operator<<для ostream - это единственный способ сделать это. В этом случае a + b может работать так:

A a;
B b

operator+(a, b);

Вот полный пример, показывающий оба способа; main() выведет '55' три раза:

#include <iostream>

struct B
{
    B(int b) : value(b) {}
    int value;
};


struct A
{
    A(int a) : value(a) {}
    int value;

    int operator+(const B& b) 
    {
        return this->value + b.value;
    }
};

int operator+(const A& a, const B& b)
{
    return a.value + b.value;
}

int main(int argc, char** argv)
{
    A a(22);
    B b(33);

    std::cout << a + b << std::endl;
    std::cout << operator+(a, b) << std::endl;
    std::cout << a.operator+(b) << std::endl;

    return 0;
}
6
ответ дан 29 November 2019 в 03:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: