Implementation of LinkedList C++ using friend I am implementing my own linkedlist in C++ as part of a class assignment. My main concern isn't with the style of the code nor the pros/cons of including or not including certain features as I am still developing member functions.

I would mainly like to know if my approach of declaring LinkedList as a friend of Node is reasonable. My decision for doing this comes from the fact that there is absolutely no need for anything to access my Node class besides LinkedList (e.g. I don't want to be able to create a Node object in main). When I do this, however, I find myself no longer needing public and private access modifiers for Node. Furthermore, I don't particularly need getter/setter methods as I can just access Node's member variables directly from LinkedList (you can see below that I don't call Node::getVal() or Node::getNext() once).

Coming from the world of Java, it seems really strange to ever access an object's internal data directly without getters/setters. What do you guys think? Does this friend relation make sense?

template &lt;typename T&gt; class Node
{
    friend class LinkedList&lt;T&gt;;
    // private:
        Node&lt;T&gt;* next;  // CAN ACCESS MEMBERS DIRECTLY BECAUSE OF FRIEND DECLARATION
        T value;
    // public:
        Node&lt;T&gt;(T valuep)
        {
            value = valuep;
            next = NULL;
        }
        void insert(T valuep)
        {
            if(next == NULL)
            {
                next = new Node&lt;T&gt;(valuep);
                return;
            }
            else
            {
                next-&gt;insert(valuep);
            }
        }

        T getVal() // DON'T NEED BECAUSE OF FRIEND DECLARATION
        {
            return value;
        }
        Node&lt;T&gt;* getNext() // DON'T NEED BECAUSE OF FRIEND DECLARATION
        {
            return next;
        }
};

template &lt;typename T&gt; class LinkedList
{
    private:
        Node&lt;T&gt;* head;
    public:
        LinkedList&lt;T&gt;()
        {
            head = NULL;
        }
        ~LinkedList&lt;T&gt;()
        {
            Node&lt;T&gt;* currentNode = head;
            while(currentNode!=NULL)
            {
                Node&lt;T&gt;* next = currentNode-&gt;next;
                delete currentNode;
                currentNode = next;
            }
        }
        void insert(T valuep)
        {
            if (head == NULL)
            {
                head = new Node&lt;T&gt;(valuep);
                return;
            }
            else
            {
                head-&gt;insert(valuep);
            }
        }

        void print()
        {
            Node&lt;T&gt;* temp = head;
            while(temp!=NULL)
            {
               std::cout &lt;&lt; temp-&gt;value &lt;&lt; std::endl; // ACCESS Node's MEMBERS DIRECTLY
               temp = temp-&gt;next; // ACCESS Node's MEMBERS DIRECTLY
            }
        }

        void update(int indexp, T valuep)
        {
            if(indexp==0)
            {
                head-&gt;value = valuep; // ACCESS Node's MEMBERS DIRECTLY
            }
        }
};
You could do this:

template&lt;typename T&gt; class LinkedList {

    struct LinkedListNode {
        T m_element;
        LinkedListNode* m_next;

        LinkedListNode(T element)
        :
        m_element{element},
        m_next{nullptr}
        {}
    };

public:

    LinkedList()
    :
    m_head{nullptr},
    m_tail{nullptr}
    {}

    void add(T element) {
        LinkedListNode* node = new LinkedListNode(element);
    }

private:
    LinkedListNode* m_head;
    LinkedListNode* m_tail;
};

int main() {
    LinkedList&lt;int&gt; l;
}


That way, your LinkedListNode implementation is not available outside of your LinkedList.