Abhishek A Udupa
Abhishek A Udupa

Reputation: 432

C++: Making a function friend of multiple classes?

Here's a Doubly Linked List class that I wrote:

template <class T>
class DLL
{
    class Node
    {
        T m_data;
        Node* m_prev;
        Node* m_next;

        Node(const T& data) :m_data{ data }, m_prev{ nullptr }, m_next{ nullptr }{}

        friend class DLL;

        friend std::ostream& operator<<(std::ostream& out, const Node& node)
        {
            out << node.m_data;
            return out;
        }
    };

    Node* m_first = nullptr;

public:
    DLL& add(const T& data)
    {
        Node* temp = new Node{ data };

        if (m_first)
        {
            temp->m_next = m_first;
            m_first->m_prev = temp;
            m_first = temp;
        }
        else {
            m_first = temp;
        }
        return *this;
    }

    friend std::ostream& operator<<(std::ostream& out, const DLL& dll)
    {
        Node* trav = dll.m_first;
        while (trav)
        {
            out << *trav << ' ';
            trav = trav->m_next; //C2248: Cannot access private member declared in class DLL::Node.
        }
        return out;
    }

    ~DLL()
    {
        Node* trav = m_first->m_next;
        Node* foll = m_first;

        while (trav)
        {
            delete foll;
            foll = trav;
            trav = trav->m_next;
        }
        delete foll;
    }
};

In the DLL's friend function to output the DLL into stream, there's an error that pops up saying the function cannot access a private member of the class Node.

After a couple of tries, I came up with a solution by declaring this friend function as a friend of the Node class as seen below:

class Node
    {
        T m_data;
        Node* m_prev;
        Node* m_next;

        Node(const T& data) :m_data{ data }, m_prev{ nullptr }, m_next{ nullptr }{}

        friend class DLL;

        friend std::ostream& operator<<(std::ostream& out, const Node& node)
        {
            out << node.m_data;
            return out;
        }

        friend std::ostream& operator<<(std::ostream& out, const DLL& dll);
    };

Now the function std::ostream& operator<<(std::ostream& out, const DLL& dll) is able to access m_next in the Node class and everything's working fine...or so I think.

My question here is: Can a function be a friend of more than one class as we see here or does what I've done invoke undefined behavior?

Upvotes: 1

Views: 401

Answers (2)

Nelfeal
Nelfeal

Reputation: 13269

A friend function declaration in some class only designates the function as a friend of that class, not as a member. You can absolutely make a function friend of multiple classes. For example:

class B;

class A {
    int a = 2;
    friend auto operator+(A a, B b) -> int;
};

class B {
    int b = 5;
    friend auto operator+(A a, B b) -> int;
};

auto operator+(A a, B b) -> int {
    return a.a + b.b;
}

Demo

Upvotes: 1

rustyx
rustyx

Reputation: 85471

Yes, a function can be a friend of more than one class.

But friends are not inherited, so even if operator<< is a friend of DLL<T> and DLL<T> a friend of DLL<T>::Node, it doesn't automatically make operator<< a friend of DLL<T>::Node, hence it can't access the private DLL<T>::Node::m_next.

The solution is to declare it a friend of DLL<T>::Node, like you did.

Upvotes: 1

Related Questions