Функции «друга» и << Перегрузка оператора: Какой правильный способ перегрузки оператора для класса?

StackOverflow https://stackoverflow.com/questions/2828280

Вопрос

В проекте я работаю, у меня есть Score класс, определенный ниже в score.h. Отказ Я пытаюсь перегрузить его так, когда << Операция выполняется на нем, _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:: Из декларации функции в BACT.CPP (эффективно не объявляю его как члена).

Почему эта работа, но бывший кусок кода не?

Спасибо за ваше время!

РЕДАКТИРОВАТЬ

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

Ниже приведен полный балл.

#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
Это было полезно?

Решение

Примечание: Возможно, вы захотите посмотреть на 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;
}

или сделать оператор friend

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;
}

Другие советы

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

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

Вы получаете ошибки компиляции, когда 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top