C ++ - должны ли функции друзей быть определены в заголовочном файле? - PullRequest
12 голосов
/ 04 декабря 2011

Я хочу перегрузить оператор << в одном из моих классов.Сигнатура выглядит следующим образом: </p>

friend std::ostream& operator<<(std::ostream& os, const Annuaire& obj)

Когда я пытаюсь определить его в файле .cpp, он говорит, что оператор << точно принимает 1 аргумент, однако, когда я определяю его в .h, онскомпилировано / работает нормально. </p>

Вот как я определяю его в файле .cpp:

std::ostream& Annuaire::operator<<(std::ostream& os, const Annuaire& obj){ // ... }

Имеет ли это какое-либо отношение к функциям друзей, которые должны быть определены в заголовочных файлах?

Ответы [ 5 ]

12 голосов
/ 04 декабря 2011

Может быть определено в файле cpp, но должно быть как минимум объявлено в заголовочном файле, в противном случае все места, где вы хотите его использовать, будут видеть тольковещи, которые дает вам сам поток, а не ваша перегрузка.

// .h and in class
friend std::ostream& operator<<(std::ostream& os, MyClass const& v);

// .cpp
std::ostream& operator<<(std::ostream& os, MyClass const& v){
    // print it
}
9 голосов
/ 04 декабря 2011

Проблема в том, как вы ее определяете. Это не член класса, это просто друг класса. Вам нужно удалить префикс Annuaire::. Итак, измените это:

std::ostream& Annuaire::operator<<(std::ostream& os, const Annuaire& obj){ // ...

к этому:

std::ostream& operator<<(std::ostream& os, const Annuaire& obj){ // ...

Причиной появления сообщения об ошибке является то, что Annuaire::operator<<(std::ostream& os, const Annuaire& obj) ожидает три аргумента: экземпляр Annuaire, к которому он вызывается (как this), и два дополнительных аргумента (os и obj).

5 голосов
/ 16 марта 2015

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

Я публикую этот ответ, потому что он не был сразу очевиден для меня.Возможно, потому что файл реализации, в который я добавлял оператор, не был полностью заключен в пространство имен, а вместо этого использовал директиву using.

Не должно быть актуально, но я использую VS2013.

//Foo.h
namespace Bar{
    class Foo
    {
    public:
        Foo();
    private:
        int n;
        friend std::ostream & operator<<(std::ostream &, Foo const &);
    };
}

//Foo.cpp
using namespace Bar; //won't apply to the operator definition
Foo::Foo(){}// doesn't require the Bar qualifier because of the using-directive

//the operator required the Bar namespace qualifier
std::ostream & Bar::operator<<(std::ostream & o, Foo const & x)
{
    return o << x.n;
}
3 голосов
/ 04 декабря 2011

Функции-друзья, даже если они кажутся объявленными внутри класса, являются не функциями-членами, а функциями уровня пространства имен (во вложенном пространстве имен). В своем коде вы правильно объявляете функцию друга, но пытаетесь определить ее как функцию-член класса:

std::ostream& Annuaire::operator<<(std::ostream& os, const Annuaire& obj){

Это определение будет для функции-члена Annuaire, называемой operator<<, которая принимает два аргумента, что недопустимо, поскольку operator<< может быть перегружено одним из двух способов: как свободная функция, принимающая два аргумента ( левая сторона и правая сторона) или как функция-член класса, который появляется в lhs выражения, принимающего аргумент типа rhs. В данном конкретном случае, поскольку lhs равен std::ostream, и вы не можете его изменить, у вас остается единственная возможность использовать свободную функцию:

std::ostream& operator<<(std::ostream& os, const Annuaire& obj)
2 голосов
/ 04 декабря 2011

Нет такого ограничения;Вы, вероятно, просто пишете это неправильно.Должно быть что-то вроде этого:

class Foo
{
   int n;

   friend std::ostream & operator<<(std::ostream &, Foo const &);
};

std::ostream & operator<<(std::ostream & o, Foo const & x)
{
   return o << x.n;
}
...