C++ - должны ли функции friend быть определены в заголовочном файле?

Я хочу перегрузить оператор

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

когда я пытаюсь определить его в рамках .cpp файл, он говорит, что оператор

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

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

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

5 ответов


может быть определена в файле 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
}

проблема в том, как вы ее определяете. Это не класс, это просто друг класса. Вам нужно отбросить 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).


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

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)

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

я публикую этот ответ, потому что он не был сразу очевиден для меня. Возможно, потому, что файл реализации, в который я добавлял оператор, не был полностью заключен в пространство имен и вместо этого использовал директиву 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;
}

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

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