This question already has answers here:
C++ operator overloading and accessing private data variables
(2 answers)
Closed 1 year ago.
I've run into an error that I don't know how to fix. My program does not compile because it outputs "declared private here". Not sure how to fix this, looking for feedback in order to improve my skills! Thanks in advance.
I've only included the areas where I am experiencing issues.
class List
{
public:
List() { first = NULL; } // constructor
List(const List& source); // copy constructor
~List(); // destructor
int length() const; // returns the length of the list that invokes it
bool present(const int& target) const;
void insert(const int& entry); // inserts the item n into the invoking list, in the appropriate position
void merge(List, List); // merges the two lists l1 and l2 into the invoking list
void makeEmpty(); // re-initializes an exisiting list to be empty
friend ostream& operator<<(ostream& out, List& c); // friend function for class
private:
struct Node
{
int data;
Node *next;
};
Node *first;
Node* get_node(const int& entry, Node* link); // allocates, initializes, and returns the address of a new node
};
ostream& operator << (ostream& out, const List& c)
{
List::Node *cursor;
out << " ";
for (cursor = c.first; cursor != NULL && cursor -> next != NULL; cursor = cursor -> next)
out << cursor -> data << ", ";
if (cursor != NULL)
out << cursor -> data;
out << " ";
return out;
}
Here is what my compiler outputs
301Project3test.cpp: In function 'std::ostream& operator<<(std::ostream&, const List&)':
301Project3test.cpp:166:11: error: 'struct List::Node' is private within this context
List::Node *cursor;
301Project3test.cpp:30:16: note: declared private here
struct Node
301Project3test.cpp:170:21: error: 'List::Node* List::first' is private within this context
for (cursor = c.first; cursor != NULL && cursor -> next != NULL; cursor = cursor -> next)
301Project3test.cpp:35:15: note: declared private here
Node *first;
List declares its friend operator<< as taking a List&, but you are implementing the operator as taking a const List& instead, so you are actually implementing a different operator, not the friend operator that has access to the private List::Node type.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
i was given the following declaration by my professor and i have a couple functions i need to write based on this declaration of LinkedList but i am stuck on determining what a couple lines of code does. i understand everything pretty much up to these lines;
friend ostream& operator<<( ostream& os, const LinkedList &ll )
{
LinkedList::Node *current;
for (current = ll.head; current != NULL; current = current->next)
os << current->data << " ";
return os;
}
here is the complete code.
#include <iostream>
#include <cstdlib>
using namespace std;
class LinkedList
{
public:
LinkedList() { head = NULL; } // default constructor makes an empty list
// functions to aid in debugging
// -----------------------------
friend ostream& operator<<( ostream& os, const LinkedList &ll );
void insertHead( int item );
private:
class Node // inner class for a linked list node
{
public:
Node( int item, Node *n ) // constructor
int data; // the data item in a node
Node *next; // a pointer to the next node in the list
};
Node *head; // the head of the list
};
friend ostream& operator<<( ostream& os, const LinkedList &ll )
{
LinkedList::Node *current;
for (current = ll.head; current != NULL; current = current->next)
os << current->data << " ";
return os;
}
void LinkedList::insertHead( int item ) // insert at head of list
{
head = new Node( item, head );
}
LinkedList::Node::Node( int item, Node *n ) {Node::data = item; next = n;}
ps. can someone also please explain what friend operator does, coz i have never used it before?
The line
friend ostream& operator<<( ostream& os, const LinkedList &ll )
overloads the "insertion operator", so you can display your list using the common C++ syntax:
std::cout << mylist;
The line above is equivalent to:
operator<<(std::cout, mylist)
The first argument is of type std::ostream, and the second one of type LikedList.
The operator needs to be a friend since it (probably) needs access to private/protected members.
See this for more details on operator overloading.
I need help with overloading '+' operator for adding together two doubly linked lists. I cannot compile my program due to getting "no match for operator=..." error. I have overloaded '=' operator already but struggle to print the result of the addition to std output. I have also overloaded the << operator. Been trying to figure out what is wrong for hours with no success. Any hints how to tackle this problem and/or solutions to it are very welcome. It is assignment for my OOP class.
Thanks in advance!
EDIT: The basic idea behind the code is to replicate set. Overloaded operators '+' should work as an union and '*' as intersection. I struggle to get the union properly printed to std output. '+=' seems to work fine. '<<' works good as well, but only when it comes to printing out single list.
EDIT:
Errors produced by compiler (g++, output from code::blocks, I have removed compiler notes):
llist3.cpp|149|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note: no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|151|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note: no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|152|error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘LList’)|
#include<iostream>
using namespace std;
class LList {
public:
struct Node {
int elem;
Node* succ;
Node* prev;
Node() : succ(0), prev(0), elem(0) {}
};
LList();
LList(LList& list);
~LList();
Node* next();
Node* begin() { curr = head; }
int getElem() { return curr->elem; }
void addElem(int elem);
LList operator+(LList& set);
LList operator+(int elem);
LList& operator+=(LList& set);
LList& operator+=(int elem);
LList& operator=(LList& list);
friend ostream& operator<<(ostream& os, LList& obj);
private:
Node* curr;
Node* head;
Node* tail;
int size;
void pushFront(Node* n);
void pushInside(Node* n);
void pushBack(Node* n);
};
LList::LList() : head(0), tail(0), size(0), curr(0) {}
LList::LList(LList& list) : size(0), curr(0), head(0), tail(0) {
list.curr = list.head;
while(list.curr) {
addElem(list.getElem());
list.next();
}
}
LList::Node* LList::next() {
if (curr)
return (curr = curr->succ);
else
return 0;
}
void LList::addElem(int elem) {
Node* n = new Node;
n->elem = elem;
if (curr) {
if (curr == head && elem < curr->elem) {
pushFront(n);
}
else if (elem > curr->elem) {
curr = curr->succ;
addElem(elem);
}
else if (elem < curr->elem && elem > (curr->prev)->elem) {
pushInside(n);
}
else if (elem < curr->elem) {
curr = curr->prev;
addElem(elem);
}
} else {
pushBack(n);
}
}
void LList::pushFront(Node* n) {
head = n;
n->succ = curr;
curr->prev = n;
n->prev = 0;
curr = n;
size++;
}
void LList::pushInside(Node* n) {
(curr->prev)->succ = n;
n->succ = curr;
n->prev = curr->prev;
curr->prev = n;
size++;
}
void LList::pushBack(Node* n) {
if (!head) {
head = n;
} else {
tail->succ = n;
n->prev = tail;
}
tail = n;
curr = n;
size++;
}
LList::~LList() {
for (curr = head; curr;) {
Node* temp = curr->succ;
delete curr;
curr = temp;
}
}
LList& LList::operator=(LList& list) {
list.begin();
if (this != &list) {
for (curr = head; curr;) {
Node* temp = curr->succ;
delete curr;
curr = temp;
}
while (list.curr) {
addElem(list.getElem());
list.next();
}
}
return *this;
}
ostream& operator<<(ostream& os, LList& list) {
LList::Node* p = list.head;
os << "{ ";
while(p) {
os << p->elem << (p->succ ? ", " : "");
p = p->succ;
}
os << " }" << endl;
return os;
}
LList LList::operator+(LList& set) {
LList temp = *this;
temp += set;
return temp;
}
LList LList::operator+(int elem) {
*this += elem;
return *this;
}
int main() {
LList setA;
setA.addElem(1234);
setA.addElem(1435);
setA.addElem(1100);
LList setB;
setB.addElem(1234);
setB.addElem(1435);
setB.addElem(5100);
setB = setA + 1234; // 1st error here
LList setD;
setD = setA + setB; //2nd
cout << setA + setB << endl; //3rd
}
There is one glaring error in your code:
Node* begin() { curr = head; }
This code invokes undefined behavior, since you are not returning a value. It should be this:
Node* begin() { curr = head; return curr; }
In addition, you should pass your LList by const reference in functions that do not change the LList parameter:
For example:
LList::LList(LList& list);
LList& operator=(LList& list);
friend ostream& operator<<(ostream& os, LList& obj);
should be:
LList::LList(const LList& list);
LList& operator=(const LList& list);
friend ostream& operator<<(ostream& os, const LList& obj);
Please change these and the other functions to pass const references. If you want to see why you should change this, you will see the issue immediately if you tried to do this:
LList list1;
LList list2;
//...
std::cout << list1 + list2;
The operator << is looking for non-const LList objects, but the addition "inline" returns a temporary LList (which will mean that the return value will be const). The code will not compile due to your overloaded operator << accepting only non-const LList.
So you need to change your parameter in operator << to a const LList&.
You have a built in "current" pointer in your list class. This is a grave design error. You are unable to define your functions correctly because of this error.
It is a design error because with this design you cannot iterate over const lists, and this means, among other bad things, that you cannot do anything useful with temporary lists. So when you calculate setA + setB, you cannot assign it to anything,because to assign you need to iterate, so you need a non-const argument to operator= and to the copy constructor. But you cannot bind a temporary to a non-const reference.
Even if you bypass the public interface in the copy constructor and the copy assignment operator, and copy the list directly without using curr, you will have the same problem with any user function that must use the public interface. That is, setA + setB will not be usable as a function argument. You will need to assign it to some variable first, and then pass that variable to the function.
You also cannot take a list and pass it down to some function in the middle of an iteration, and expect to continue to iterate from the place you've left, because anything that iterates the list changes the curr pointer.
The best solution is to get rid of the curr member and make most of your arguments const LList&. While this is not the onky solution, there are many other drawbacks to having a current pointer built into a list class so I won't talk about them.
In order to iterate the list, you have to supply a separate object that can go back and forth over the list, and a separate variant of it that can go back and forth over a const list. This is called an iterator and you need to read up on this concept if you want to do anything in C++.
In your case iterators can be Node* and const Node*. You only need to provide member functions that return the first node in the list, which you already have. Real libraries do the same. They normally wrap the node pointer in a separate iterator class, for various reasons; but for a simple homework this is not necessary (though you can do it if you want).
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have a linked list of a struct:
typedef struct {
std::string title;
int rating;
} listing;
and a standard iterator that's part of my list's class:
template<class T>
class ListIterator
{
public:
ListIterator( ) : current(NULL) {}
ListIterator(Node<T>* initial) : current(initial) {}
const T& operator *( ) const { return current->getData( ); }
//Precondition: Not equal to the default constructor object,
//that is, current != NULL.
ListIterator& operator ++( ) //Prefix form
{
current = current->getLink( );
return *this;
}
ListIterator operator ++(int) //Postfix form
{
ListIterator startVersion(current);
current = current->getLink( );
return startVersion;
}
bool operator ==(const ListIterator& rightSide) const
{ return (current == rightSide.current); }
bool operator !=(const ListIterator& rightSide) const
{ return (current != rightSide.current); }
//The default assignment operator and copy constructor
//should work correctly for ListIterator,
private:
Node<T> *current;
};
this works fine when dealing with lists of standard data types (int, char, string, etc.) but I can't figure out how to iterate through the data in each struct within the list.
It could be due to how I'm storing them:
// declaration of list, Queue is list class name
Queue<listing> list;
// data reads from file
while (!datafile.eof()) {
listing entry = *new listing;
datafile >> listing.rating;
std::getline(datafile, listing.title);
list.add(entry);
}
Hope this isn't too vague. If you need to see more code let me know.
Node and Queue class:
template<class T>
class Node
{
public:
Node(T theData, Node<T>* theLink) : data(theData), link(theLink){}
Node<T>* getLink( ) const { return link; }
const T& getData( ) const { return data; }
void setData(const T& theData) { data = theData; }
void setLink(Node<T>* pointer) { link = pointer; }
private:
T data;
Node<T> *link;
};
template<class T>
class Queue
{
public:
typedef ListIterator<T> Iterator;
Queue( );
// Initializes the object to an empty queue.
Queue(const Queue<T>& aQueue);
Queue<T>& operator =(const Queue<T>& rightSide);
virtual ~Queue( );
void add(T item);
// Postcondition: item has been added to the back of the queue.
T remove( );
// Precondition: The queue is not empty.
// Returns the item at the front of the queue
// and removes that item from the queue.
bool isEmpty( ) const;
// Returns true if the queue is empty. Returns false otherwise.
Iterator begin() const { return Iterator(front); }
Iterator end() const { return Iterator(); }
private:
Node<T> *front; // Points to the head of a linked list.
// Items are removed at the head
Node<T> *back; // Points to the node at the other end of the linked list.
// Items are added at this end.
};
The solution was pretty simple. I'm embarrassed I didn't see it earlier.
Queue<listing>::Iterator all;
for (all = list.begin(); all != list.end(); all++) {
listing entry = *all;
cout << entry.title << " ";
cout << entry.rating << "\n";
}
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.
I have the following main.cpp file
#include "listtemplate.h"
//#include <iostream>
using namespace std;
int main()
{
int UserChoice;
cout << "Hello, World!" << endl;
cin >> UserChoice;
cout << UserChoice;
}
In it's current form, everything works. I enter an integer, and that integer is printed to the screen. However, when I uncomment the cout << "Hello, World!" << endl line, I get the following error
main.cpp:10: error: ambiguous overload for ‘operator<<’ in ‘std::cout << "Hello, World!"’
I can also make it work by commenting out #include "listtemplate.h", uncommenting the hello world line, and including <iostream> in main (currently accessible through the template. Can anyone see what I'm missing here?
listtemplate.h
#ifndef LISTTEMPLATE_H
#define LISTTEMPLATE_H
#include "list.h"
using namespace std;
// Default constructor
template <class Type>
list<Type> :: list() : Head(NULL) {}
// Destructor
template <class Type>
list<Type> :: ~list()
{
Node *Temp;
while (Head != NULL)
{
Temp = Head;
Head = Head -> Next;
delete Temp;
}
}
// Copy constructor
template <class Type>
list<Type> :: list (const Type& OriginalList)
{
Node *Marker;
Node *OriginalMarker;
OriginalMarker = OriginalList.Gead;
if (OriginalMarker == NULL) Head = NULL;
else
{
Head = new Node (OriginalMarker -> Element, NULL);
Marker = Head;
OriginalMarker = OriginalMarker -> Next;
while (OriginalMarker != NULL)
{
Marker -> Next = new Node (OriginalMarker -> Next);
OriginalMarker = OriginalMarker -> Next;
Marker = Marker -> Next;
}
}
}
// Copy assignment operator
template <class Type>
list<Type>& list<Type> :: operator= (const list<Type>& Original)
{
Node *Marker;
Node *OriginalMarker;
// Check that we are not assigning a variable to itself
if (this != &Original)
{
// First clear the current list, if any
while (Head != NULL)
{
Marker = Head;
Head = Head -> Next;
delete Marker;
}
// Now build a new copy
OriginalMarker = Original.Head;
if (OriginalMarker == NULL) Head = NULL;
else
{
Head = new Node (OriginalMarker -> Element, NULL);
Marker = Head;
OriginalMarker = OriginalMarker -> Next;
while (OriginalMarker != NULL)
{
Marker -> Next = new Node (OriginalMarker -> Element, NULL);
OriginalMarker = OriginalMarker -> Next;
Marker = Marker -> Next;
}
}
}
return (*this);
}
// Test for emptiness
template <class Type>
bool list<Type> :: Empty() const
{
return (Head == NULL) ? true : false;
}
// Insert new element at beginning
template <class Type>
bool list<Type> :: Insert (const Type& NewElement)
{
Node *NewNode;
NewNode = new Node;
NewNode -> Element = NewElement;
NewNode -> Next = Head;
return true;
}
// Delete an element
template <class Type>
bool list<Type> :: Delete (const Type& DelElement)
{
Node *Temp;
Node *Previous;
// If list is empty
if (Empty()) return false;
// If element to delete is the first one
else if (Head -> Element == DelElement)
{
Temp = Head;
Head = Head -> Next;
delete Temp;
return true;
}
// If the list has only one element which isn't the specified element
else if (Head -> Next == NULL) return false;
// Else, search the list element by element to find the specified element
else
{
Previous = Head;
Temp = Head -> Next;
while ((Temp -> Element != DelElement) && (Temp -> NExt != NULL))
{
Previous = Temp;
Temp = Temp -> Next;
}
if (Temp -> Element == DelElement)
{
Previous -> Next = Temp -> Next;
delete Temp;
return true;
}
else return false;
}
}
// Print the contents of the list
template <class Type>
void list<Type> :: Print (ostream& OutStream) const
{
Node *Temp;
Temp = Head;
while (Temp != NULL)
{
OutStream << Temp -> Element << " ";
Temp = Temp -> Next;
}
}
// Overloaded output operator
template <class Type>
ostream& operator<< (ostream& OutStream, const list<Type>& OutList)
{
OutList.Print (OutStream);
return OutStream;
}
#endif
list.h
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include <cstddef>
using namespace std;
template <class Type>
class list
{
private:
struct Node
{
public:
Type Element;
Node *Next;
Node() : Next(NULL) {} // Default constructor
Node (Type Data, Node *PNode = NULL) : // Non-default constructor
Element (Data),
Next (PNode) {}
};
Node *Head;
public:
list();
~list();
list (const Type& OriginalList);
bool Empty() const;
bool Insert (const Type& NewElement);
bool Delete (const Type& DelElement);
void Print (ostream& OutStream) const;
list& operator= (const list<Type>& Original);
};
template <class Type>
ostream& operator<< (ostream& OutStream, const Type& OutList);
#endif
This is in fact an interesting question. The main issue is, as others have pointed before that you have declared the following signature:
template <typename T>
std::ostream& operator<<( std::ostream&, T const & );
And that triggers the ambiguity, as it is a catch-all template. But why is it that the compiler can insert (unambiguously) an integer into cout but it cannot insert a const char*?
The reason for that is in the definition of the std::basic_ostream template and free functions that are required in the standard. In particular, the template class basic_ostream contains member functions to insert basic types, including int. On the other hand, the insertion of const char* into streams is defined as a templated free function. Bringing the three declarations together:
namespace std {
template <typename CharT, typename traits = char_traits<CharT> >
class basic_ostream {
// ...
basic_ostream<CharT,traits>& operator<<(int n); // [1]
// ...
};
template<class charT, class traits> // [2]
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const char*);
}
template <typename T> // [3]
std::ostream& operator<<( std::ostream&, T const & ); // user defined
Now, when the compiler encounters the expression std::cout << 5, it finds that [1] is a non-templated perfect match. It is non-templated as std::cout is an object of a concrete instantiation of the basic_ostream class template, when the compiler considers the members of that class, the type is fixed. The method itself is not templated.
The template [3] could match the same use, but because [1] is not templated it takes precedence in the overload resolution, and there is no ambiguity.
Now, when the compiler sees the expression std::cout << "Hello world";, it performs the lookup and it finds (among other options that cannot be matched and are thus discarded) options [2] and [3]. The problem is that now, both options are templates, the first one can be resolved by matching CharT = char and traits = char_traits<char>, while the second can be matched by making T = const char* (the first argument is a concrete instantiated type). The compiler cannot make up its mind (there is no partial order that defines which option it should follow), and it triggers the ambiguity error.
The really interesting point in the question is that while both [1] and [2] seem to be templated on the arguments CharT and traits basically in the same way they are not considered in the same way by the compiler, the reason for that is that lookup finds [1] as a member of std::cout, that means that in [1], basic_ostream<char,char_traits<char> > is the concrete known type of the first argument and it is fixed. The template is the class, not the function, and the class instantiation types are fixed before lookup considers the member functions. On the other hand, when it ADL finds [2] and tries to match against the call, basic_ostream<CharT, traits> is a generic type that can be matched to the type of cout.
I hope this is not too confusing, but I think it is nice to know the subtle difference of similarly looking code.
I think that the problem is that in your header you've prototyped this function:
template <class Type>
ostream& operator<< (ostream& OutStream, const Type& OutList);
instead of this one:
template <class Type>
ostream& operator<< (ostream& OutStream, const list<Type>& OutList);
The version you've prototyped says that it's an operator << that can print out anything, not lists of anything. Consequently, when you write
cout << "Hello, world!" << endl;
The compiler can't tell which function it's supposed to call - the standard output function or the one you've defined in your list header.
declared as:
ostream& operator<< (ostream& OutStream, const Type& OutList);
in the function definition as:
ostream& operator<< (ostream& OutStream, const list<Type>& OutList)