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

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?

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.

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

Related

Overloading ostream << operator for a class with private key member

I am trying to overload the ostream << operator for class List
class Node
{
public:
int data;
Node *next;
};
class List
{
private:
Node *head;
public:
List() : head(NULL) {}
void insert(int d, int index){ ... }
...}
To my humble knowledge (overload ostream functions) must be written outside the class. So, I have done this:
ostream &operator<<(ostream &out, List L)
{
Node *currNode = L.head;
while (currNode != NULL)
{
out << currNode->data << " ";
currNode = currNode->next;
}
return out;
}
But of course, this doesn't work because the member Node head is private.
What are the methods that can be done in this case other than turning Node *head to public?
You can solve this by adding a friend declaration for the overloaded operator<< inside class' definition as shown below:
class List
{
//add friend declaration
friend std::ostream& operator<<(std::ostream &out, List L);
//other member here
};
Declare the function signature inside the class and mark it as friend, then define it outside the class if you want.

I looking for advice on whether it's better to use a friend or write a getter, but (sort of) break the encapsulation?

i have a class:
template <typename T>
class List {
private:
struct pointNode {
T data;
pointNode* next;
pointNode* prev;
pointNode() :data(0), next(nullptr), prev(nullptr) {}
pointNode(T n_data) : data(n_data), next(nullptr), prev(nullptr) {}
const T& getValue() {
return this->data;
}
};
pointNode* head;
pointNode* tail;
public:
class Iterator {
//friend class List;
using Iterator_type = List<T>::pointNode;
public:
Iterator(Iterator_type* rNode) {
current_node = rNode;
}
bool operator !=(const Iterator& pNode) {
return this->current_node != pNode.current_node;
}
T const get_value() {
return this->current_node->data;
}
private:
Iterator_type* current_node;
};
List() : head(nullptr), tail(nullptr) {}
inline void InsertFront(T&& val);
inline void InsertBack(T&& val);
inline bool is_empty();
inline void Insert_after_v(T&&searchVal,T&&val);
inline void Insert_after_p(int pos, T&& val);
};
I'm trying to write a function that inserts an element after a given:
template<typename T>
inline void List<T>::Insert_after(Iterator pos, T&& val)
{
pointNode* new_node = new pointNode(std::move(val), ... );
}
as the 2 parameters of the constructor pointNode,i need to get the value of the iterator
private:
Iterator_type* current_node;
And I think it's the right thing to do ?make a friend:
struct pointNode {
friend class Iterator
But I often see that friend is not a particularly good style.
class Iterator
{
public:
Iterator_type* get_current_node() const {
return current_node;
}
or write something like this :
class Iterator
{
public:
Iterator_type* get_node() const {
return current_node;
}
But it seems to me that it is not very good to let the user get private data.So maybe who knows how to do the right thing in such situations?I would be grateful for your advice

error C2244 unable to match function definition to an existing declaration in cpp /// operator overloading

I am trying to overload =+ operator. there are two of it. One for the linkedlist+=linkedlist, other for the linkedlist+=templated type. But vs gives me an error.
template <class T>
const DList<T>& DList<T>::operator += (const DList & rhs)
{
Node<T> temp=head;
while(temp->next!=NULL)
{
temp=temp->next;
}
rhs.head->prev=temp;
temp->next=rhs.head;
return *this;
}
template <class T>
DList<T>& DList<T>::operator += (T n)
{
Node<T> * temp= new Node<T>(n, NULL, head);
head=temp;
return *this;
}
Here the entire header:
#ifndef _DList_H
#define _DList_H
template <class T>
struct Node
{
T val;
Node<T>* next;
Node<T>* prev;
Node(T el, Node<T>* p=NULL, Node<T>* n=NULL ): val(el), prev(p), next(n)
{};
};
template <class T>
class DList
{
private:
Node<T>* head;
int size;
public:
const DList & DList::operator += (const DList & rhs);
DList();
DList(const DList&);
~DList();
bool isEmpty();
void printList() const;
void addToBeginning(T n);
void deleteList ();
const DList<T> & DList::operator = (const DList & rhs);
const DList<T> & DList::operator += (T);
const DList<T> & DList::operator -= (T);
bool DList<T>::operator < (const DList & rhs);
bool DList<T>::operator > (const DList & rhs);
bool DList<T>::operator == (const DList & rhs);
Node<T> * createClone () const;
};
#include "DList.cpp"
#endif
Btw, it's my first question. I hope that asked it clearly and used the format correctly.
The full error message:
Error 1 error C2244: 'DList::+=' : unable to match function definition to an existing declaration
+= operator used like this:
list4 += list1 += list2;
list1 -= 5;
list1 -= 6;
If you are using templates, you cannot separate function defintion from declaration.
The DList:: prefix may not be in the function declaration within the class body.
You should not inculde cpp files. These files should include header files to make declarations available for the compiler.

function of class Y is not a member of X, but class X is a friend of Y

There is a similar question to this with the function being an operator overload with arguments and that is the main emphasis, which is only confusing me further.
I am simply trying to execute a short recursive function on a tree class that gets called on non-empty Node objects in order to traverse down the tree's child nodes respectively.
My class declarations are as such:
template<class T>
class BTNode {
template<class I>
friend class BST;
T data;
BTNode<T>* left_;
BTNode<T>* right_;
...
}
template<class I>
class BST {
BTNode<I>* root_;
BTNode<I>* curr_;
BTNode<I>* parent_;
int currSize = 0;
public:
size_t size() const {
if (root_ == NULL) {
return currSize;
}
else {
BTNode<I>* left_ = root_->getLeft();
BTNode<I>* right_ = root_->getRight();
if (left_ != NULL)
currSize += left_->size();
if (right_ != NULL)
currSize += right_->size();
}
return currSize;
}
...
};
The error as it stands is:
'size()': is not a member of 'BTNode<I>'
So far, I have tried make BTNode a friend class of BST, and the error still prevails (having both classes become friends of each other).
Thanks in advance.
You misunderstand what friend declarations do. Saying that A is a friend of B means that A gains access to protected and private members of B. It allows A to call private functions of B, for example. It does not extend the interface of A or B in any way.
If I understand correctly what you're trying to achieve, you should be able to do that by having size take a parameter:
template<class I>
class BST {
BTNode<I>* root_;
BTNode<I>* curr_;
BTNode<I>* parent_;
public:
size_t size() const {
return size_(root_);
}
private:
static size_t size_(const BTNode<I> *node) {
if (node == NULL) {
return 0;
}
else {
return 1 + size_(node->getLeft()) + size_(node->getRight());
}
}
...
};

Linked List output crash

My program hangs when outputting contents of my linked list. I can't change the header, only the cpp file.
playlist.h:
class PlayList {
private:
struct SongNode {
Song data;
SongNode* next;
SongNode (const Song& s, SongNode* nxt = 0)
: data(s), next(nxt)
{}
};
friend std::ostream& operator<< (std::ostream& out, const PlayList& s);
SongNode* first; // head of a list of songs, ordered by title, then artist
//Snip...
inline
std::ostream& operator<< (std::ostream& out, const PlayList& pl)
{
for (PlayList::SongNode* current = pl.first; current != 0; current = current->next)
out << current->data << std::endl;
return out;
}
playlist.cpp
using namespace std;
PlayList::PlayList()
: totalTime(0,0,0)
{
}
void PlayList::operator+= (const Song& song)
{
SongNode* newNode = new SongNode(song, first);
first = newNode;
}
When outputting the list all of the data that is supposed to print, does print, but then the program hangs.
In the constructor of class PlayList, you need to initialise first:
public:
PlayList() : first(NULL) {}
Otherwise, in your operator<<, you reach the end of the list and instead of encountering NULL, you just get a junk pointer.
You forgot to initialize first in the constructor.