I have to overload the insertion operator in order to view my class objects in matrix format. I wrote the code but something's wrong. When I include this to my code and trying to build, compiler gives me tons of errors; when I commented that part out, the errors are gone and program works correctly. Here is the code:
template <class itemType>
ostream & operator<< (ostream & os, const Storage2D<itemType> & rhs)
{
node<itemType>* ptrRow = rhs.head;
node<itemType>* ptrColumn = rhs.head;
for(; ptrColumn->down != NULL; ptrColumn = ptrColumn->down)
{
ptrRow = ptrColumn;
for(; ptrRow->right != NULL; ptrRow = ptrRow->right)
{
os << ptrRow->info << setw(10);
}
os << ptrRow->info << setw(10) << endl;
}
return os;
}
Here is how I tried to use overloading from main function:
Storage2D<double> m(row, column);
cout << m;
It is not the member function of class Storage2D, it is written outside of the scope of class Storage2D in the implementation file.
It would be great if you help me, thanks in advance.
EDIT: Here is the rest of my code. The Storage2D.h file:
template <class itemType>
struct node
{
itemType info;
node* right;
node* down;
node()
{}
node(itemType data, node* r = NULL, node* d = NULL)
{
info = data;
right = r;
down = d;
}
};
template <class itemType>
class Storage2D
{
public:
Storage2D(const int & , const int & ); //constructor
//~Storage2D(); //destructor
//Storage2D(const Storage2D & ); //deep copy constructor
private:
node<itemType>* head;
};
ostream& operator<< (ostream & os, const Storage2D & rhs);
#include "Storage2D.cpp"
head is private so the operator needs to be a friend so it can access that data member. It also needs to be declared as a function template since Storage2D is a class template:
#include <iostream> // for std::ostream
template <class itemType>
class storage2D {
// as before
template <typename T>
friend std::ostream& operator<< (std::ostream & os, const Storage2D<T> & rhs);
};
// declaration
template <typename T>
std::ostream& operator<< (std::ostream & os, const Storage2D<T> & rhs);
Note that I have explicitly used std::ostream, since ostream is in the std namespace.
Related
I have the following class declaration:
#ifndef ANIL_CURSOR_LIST_H
#define ANIL_CURSOR_LIST_H
#include <cstddef>
#include <iostream>
namespace anil {
class cursor_list_node {
private:
int data;
cursor_list_node* next;
cursor_list_node* previous;
friend class cursor_list;
};
class cursor_list {
private:
// Data:
int m_index;
int m_size;
cursor_list_node* front;
cursor_list_node* back;
cursor_list_node* cursor;
// Functions:
void delete_list();
public:
cursor_list() : m_index(-1), m_size(0), front(nullptr), back(nullptr),
cursor(nullptr) {}
cursor_list(cursor_list& copied_list);
bool is_empty();
int size();
int index();
int front_data();
int back_data();
int cursor_data();
bool operator==(cursor_list& rhs); // rhs = right hand side
cursor_list& operator= (cursor_list& rhs); // rhs = right hand side
friend std::ostream& operator<<(std::ostream& out, cursor_list& rhs); // rhs = right hand side
void clear();
void move_cursor_front();
void move_cursor_back();
void move_cursor_prev();
void move_cursor_next();
void prepend(int new_data);
void append(int new_data);
void insert_before_cursor(int new_data);
void insert_after_cursor(int new_data);
void delete_front();
void delete_back();
void delete_cursor();
~cursor_list();
};
}
#endif /* ANIL_CURSOR_LIST_H */
And inside the .cpp file I have the following code for the <<operator:
std::ostream& operator<<(std::ostream& out, anil::cursor_list& rhs) {
if (rhs.is_empty() != false) {
anil::cursor_list_node* back_up_cursor = rhs.cursor;
int back_up_index = rhs.index();
for (rhs.move_cursor_front(); rhs.index() >= 0; rhs.move_cursor_next()) {
if (rhs.cursor == rhs.front) {
out << rhs.cursor_data();
} else {
out << ' ' << rhs.cursor_data();
}
}
rhs.m_index = back_up_index;
rhs.cursor = back_up_cursor;
}
}
Although I declared <<operator as a friend of the class cursor_list, I am unable to access the private member using the class_instance.private_member method. Can someone point out what I am doing wrong?
You need to define operator<< in the anil namespace.
namespace anil {
std::ostream& operator<<(std::ostream& out, cursor_list& rhs) {
// ...
return out; // don't forget this
}
}
An easier option is often to just define the friend function inline:
class cursor_list {
// ...
friend std::ostream& operator<<(std::ostream& out, cursor_list& rhs) {
// ...
return out;
}
};
It's also quite unusual to have non-const right hand side arguments to operator<< and I noticed that empty() and index() etc. are also non-const. Perhaps you have reasons for that, but it's worth a note.
While trying to create a Binary Search Tree (BST) using C++11 I hit a snag.
I can't extract a properly created BST out of the function where it is created.
The function reads data from a file (in this case just a number on each line) and builds a BST from those. The building part in the loop works correctly.
The problem is I can't get the temporary object moved where I want it to be.
Zooming in on the problem I think, see edit 3.
More context:
BST<T> is a class that derives publicly from std::unique_ptr<BSTknoop<T>>
BST<T> also inherits the constructors of unique_ptr<BSTknoop<T>> with
template<class T>
using BSTknoopptr=std::unique_ptr<BSTknoop<T>>; // alias template
and
using BSTknoopptr<T>::BSTknoopptr; // in the body of the BST<T> class declaration`
A BSTknoop<T> is a data structure with 3 fields
one T object to hold the node data
two BST<T> objects left and right (each child is a tree in its own right)
the goal is to move my newly created BST into the calling object. The idea is that in main you can call BST<int> tree; tree.lees(ifs); (with ifs an open input filestream) and tree holds the properly filled BST afterwards.
The function:
template<class T>
istream& BST<T>::lees(istream& is){
string lijn;
T knoopwaarde;
getline(is,lijn);
knoopwaarde = stoi(lijn);
BST<T> temptree(new BSTknoop<T>());
temptree->sl = knoopwaarde;
for(int i=1; i<DATA_SET_LENGTH ; i++){
getline(is,lijn);
knoopwaarde=stoi(lijn);
temptree.add(knoopwaarde);
cout<<temptree;
}
this->swap(temptree); /* This does not work */
/* *this = move(temptree); this does not work either*/
return is;
}
I have also tried to return a BST<T> from the function and moving that result in the main. That didn't work either.
The program crashes at runtime with an unknown signal.
Side note: I'm unsure as to why BST<T> temptree(new BSTknoop<T>()); works in regard to the templating. The construction works because BST<T> inherits the constructors for unique_ptr<BSTknoop<T>>
edit 1: the declaration of the BST<T> class:
template <class T>
class BST:public BSTknoopptr<T>{
using BSTknoopptr<T>::BSTknoopptr;
public:
friend istream& operator>>(istream& is, BST<T>& bb){
return bb.lees(is);
}
friend ostream& operator<<(ostream& os, const BST<T>& bb){
//return bb.schrijflevelorder(os);
return bb.schrijfKnoop(os);
}
void add(const T&);
ostream& schrijf(ostream&);
ostream& schrijfKnoop(ostream&) const;
int aantalSleutels() const;
istream& lees(istream&);
ostream& schrijflevelorder(ostream& os) const;
private:
};
the declaration of theBSTknoop<T> class:
template <class T>
class BSTknoop{
friend class BST<T>;
public:
BSTknoop() {}
explicit BSTknoop(T _sl) : sl(_sl) {}
private:
T sl;
BST<T> links,rechts;
};
edit 2: I've written a move constructor and move assignment operator. I've made sure to retain the default constructor as well using BST<T>()=default; I'm confused though: the BST class doesn't have any members for which I would have to implement my own move constr / operator.
However, BST has inherited from unique_ptr<BSTknoop<T>>so implicitly, it must hold a member of that type. Suppose I want to keep the inheritance, is there any neat way to make this work?
Is is also true that I can't (or perhaps shouldn't) implement a copy constr / operator as those are deleted for unique_ptr?
template<class T>
BST<T>::BST(BST<T>&& other){
*this = move(other);
}
template<class T>
BST<T>& BST<T>::operator=(BST<T>&& other){
cout<<"called move operator BST"<<endl;
(*this).BSTknoopptr<T>::operator=(move(other));
return *this;
}
edit 3: with my own move constr / operator, the temptree no longer gets filled properly. Below is my code for add which is used to build the tree. If I omit my own move constr / operator, then this works. What I need is an operation that works like this->get()->links = move(tmp).
types this->get()->links => BST<T>
tmp => BST<T>
How come this works? It does the operation I need, why can't I use something similar to do *this = move(temptree) by writing the operation myself.
template<class T>
void BST<T>::add(const T& value){
if(value <= this->get()->sl){
if(this->get()->links != nullptr){
this->get()->links.add(value);
}
else {
BST<T> tmp(new BSTknoop<T>(value));
this->get()->links = move(tmp);
}
}
else{
if(this->get()->rechts != nullptr){
this->get()->rechts.add(value);
}
else{
BST<T> tmp(new BSTknoop<T>(value));
this->get()->rechts = move(tmp);
}
}
}
Okay, I made the stupidest mistake. There is nothing wrong with the inheritance and accompanying move semantics. I used the DATA_SET_LENGTH preprocessor directive inside my istream& BST<T>::lees(istream& is) function. While my final dataset will hold a million items. My dataset for testing purposes only holds 12. I forgot to change the value of DATA_SET_LENGTH so stoi(lijn) crashed.
For anyone interested in the solution:
notes
You don't need to write much code to make this work.
It is possible to write BST<T>& operator=(BSTknoopptr<T>&&); yourself and it works. However even without explicitly writing your own it also works.
The BST class has no fields of pointer type so we don't get into trouble with unique_ptr not having a virtual destructor
Final question (perhaps someone can comment):
The inherited operator operator=(BSTknoopptr<T>&&), what does its signature look like in BST<T>? Mostly in regards to return type (if it's now a member of BST<T> what type does it return?).
** TLDR: why can I rely on the inherited move operator / move constructors of unique_ptr<BSTknoop<T>>? **
bst.h
#define DATA_SET_LENGTH 12
using namespace std;
template <class T>
class BST;
template <class T>
class BSTknoop;
template<class T>
using BSTknoopptr=std::unique_ptr<BSTknoop<T>>;
template <class T>
class BST:public BSTknoopptr<T>{
using BSTknoopptr<T>::BSTknoopptr;
public:
BST<T>& operator=(BST<T>&&) = default;
BST<T>(BST<T>&&) = default;
BST<T>()=default;
//BST<T>& operator=(BSTknoopptr<T>&&);
friend istream& operator>>(istream& is, BST<T>& bb){
return bb.lees(is);
}
friend ostream& operator<<(ostream& os, const BST<T>& bb){
//return bb.schrijflevelorder(os);
return bb.schrijfKnoop(os);
}
void add(const T&);
//schrijf schrijft uit in een vorm die min of meer menselijk leesbaar is
ostream& schrijf(ostream&);
ostream& schrijfKnoop(ostream&) const;
int aantalSleutels() const;
istream& lees(istream&);
//schrijflevelorder schrijft uit in een vorm die door lees(...) kan gelezen worden.
ostream& schrijflevelorder(ostream& os) const;
private:
};
template <class T>
class BSTknoop{
friend class BST<T>;
public:
BSTknoop() {}
explicit BSTknoop(T _sl) : sl(_sl) {}
private:
T sl;
BST<T> links,rechts;
};
//template<class T>
//BST<T>& BST<T>::operator=(BSTknoopptr<T>&& other){
// cout<<"called BST<T> move with BSTknoopptr r-value ref argument"<<endl;
// (*this).BSTknoopptr<T>::operator=(move(other));
// return *this;
//}
template<class T>
void BST<T>::add(const T& value){
if(value <= this->get()->sl){
if(this->get()->links != nullptr){
this->get()->links.add(value);
}
else {
//BSTknoopptr<T> tmp(new BSTknoop<T>(value)); if used with my own BST<T>& BST<T>::operator=(BSTknoopptr<T>&& other)
BST<T> tmp(new BSTknoop<T>(value));
this->get()->links = move(tmp);
}
}
else{
if(this->get()->rechts != nullptr){
this->get()->rechts.add(value);
}
else{
//BSTknoopptr<T> tmp(new BSTknoop<T>(value)); if used with my own BST<T>& BST<T>::operator=(BSTknoopptr<T>&& other)
BST<T> tmp(new BSTknoop<T>(value));
this->get()->rechts = move(tmp);
}
}
}
template<class T>
istream& BST<T>::lees(istream& is){
string lijn;
T knoopwaarde;
getline(is,lijn);
knoopwaarde = stoi(lijn);
BST<T> temptree(new BSTknoop<T>());
temptree->sl = knoopwaarde;
for(int i=1; i<DATA_SET_LENGTH ; i++){
getline(is,lijn);
knoopwaarde=stoi(lijn);
temptree.add(knoopwaarde);
cout<<temptree;
}
*this = move(temptree);
return is;
}
main.cpp
int main(){
ifstream ifs;
ifs.open("c.dat");
if(ifs.is_open()){
BST<int> tree;
tree.lees(ifs);
tree.schrijfKnoop(cout);
}
else {
cerr<<"failed to open file"<<endl;
return -1;
}
}
I tried to search but I couldn't find a solution and what is the meaning of the problem.
friend ostream & operator<<(ostream &os, const BST<T> &rhs);
void helperFunc(ostream & os, Node<T> *root) const;
and the definition is:
template<class T>
ostream & operator<<(ostream & os, const BST<T> &rhs)
{
rhs.helperFunc(os, rhs._root);
os << endl;
return os;
}
template<class T>
void BST<T>::helperFunc(ostream & os, Node<T> *root) const
{
if (root != NULL)
{
helperFunc(os, root->left);
os << root->value << " ";
helperFunc(os, root->right);
}
}
In main I'm using:
void main()
{
BST <int> a;
a.insert(5)
cout << a;
}
And I'm getting the following error message:
Error LNK2019 unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class BST<int> const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$BST#H###Z) referenced in function _main...
Any additional info will be supplied if required.
The solution was:
template <typename U>
friend ostream & operator<<(ostream & os, const BST<U> &obj);
Overloading operator<< and operator>> in template class is a little special. Just comment this declaration and it will work:
friend ostream & operator<<(ostream &os, const BST<T> &rhs);
This is because the friend function is not a member function of the class actually. The overloaded operator<< function defined outside the class actually defines a new template function, different from that declared in the class. Although they have the same 'template class T', but indeed they are different functions. So the compile error tells you that the operator<< function of the class is not defined.
Since we have overload a new template operator<< outside the class, we can just get rid of the friend function declared in the class. The follow codes will work and I change some other functions for well explanation:
#include <iostream>
using namespace std;
template<class T>
class Node {
};
template<class T>
class BST {
public:
// friend ostream & operator<<(ostream & os, const BST<int> &rhs);
void helperFunc(ostream & os, Node<T> *root) const;
};
template<class T>
ostream & operator<<(ostream & os, const BST<T> &rhs)
{
cout << "success" << endl;
// rhs.helperFunc(os, rhs._root);
// os << endl;
return os;
}
template<class T>
void BST<T>::helperFunc(ostream & os, Node<T> *root) const
{
if (root != NULL)
{
helperFunc(os, root->left);
os << root->value << " ";
helperFunc(os, root->right);
}
}
int main()
{
BST<int> a;
// a.insert(5);
cout << a;
}
I'm trying to overload operator<< in C++ to use a recursive private method to get the content of a binary search tree as a string. I keep getting the "not declared in this scope" error despite checking the method signature for inconsistencies. I don't understand why the call to recursiveOutput() in operator<< causes this error.
operator<< definition:
friend std::ostream& operator<<(std::ostream&, const BinTree&);
recursive method definition:
void recursiveOutput(Node*, string&);
operator<< implementation:
std::ostream& operator<<(std::ostream& os, const BinTree& rhs)
{
string result;
recursiveOutput(rhs.root, result);
os << result;
return os;
}
The BinTree class has the private member "root" which is a pointer to the structure "Node".
EDIT: Example code
class BinTree
{
public:
friend std::ostream& operator<<(std::ostream&, const BinTree&);
private:
struct Node
{
string data;
Node* left;
Node* right;
};
Node* root;
void recursiveOutput(Node*, string&);
};
std::ostream& operator<<(std::ostream& os, const BinTree& rhs)
{
string result;
rhs.recursiveOutput(rhs.root, result);
os << result;
return os;
}
void BinTree::recursiveOutput(Node* currentRoot, string& result)
{
// if currentRoot is NULL return
if (currentRoot == NULL)
{
return;
}
// traverse left branch
recursiveOutput(currentRoot->left, result);
// append string from NodeData
std::ostringstream stream;
stream << *currentRoot->data;
result.append(stream.str());
result.append(" ");
// traverse right branch
recursiveOutput(currentRoot->right, result);
}
EDIT: The reason this causes an error is because operator<< is not a member of BinTree, so it cannot call a member function without a BinTree object to call it.
I am writing a class for a linked list in C++ and I am having an issue when writing the operator overload for <<. My class' header is:
class LList
{
private:
struct LNode
{
LNode ();
int data;
LNode * next;
};
public:
LList ();
LList (const LList & other);
~LList ();
LList & operator = (const LList & other);
bool operator == (const LList & other);
int Size () const;
friend ostream & operator << (ostream & outs, const LList & L);
bool InsertFirst (const int & value);
bool InsertLast (const int & value);
bool DeleteFirst ();
bool DeleteLast ();
private:
LNode * first;
LNode * last;
int size;
};
and the operator is:
ostream & operator << (ostream & outs, const LList & L){
LNode *np;
np=L.first;
while(np!=NULL){
outs<<np->data;
np=np->next;
}
return outs;
}
When I compile the code I get an error:
LList.cpp: In function ‘std::ostream& operator<<(std::ostream&, const LList&)’:
LList.cpp:36:2: error: ‘LNode’ was not declared in this scope
LNode *np;
^
LList.cpp:36:9: error: ‘np’ was not declared in this scope
LNode *np;
I thought I could instantiate a struct inside a friend function but it looks like that doesn't work. Any of you know what is happening?
Since your operator<< is a global function, you need to access your inner class with:
LList::LNode *np;
Since this function is a friend of LList, then it can access the private LNode class.
Since the operator<< overload is a non-member function, you'll need to use LList::LNode.
ostream & operator << (ostream & outs, const LList & L){
LList::LNode *np;
// ^^^^^
np=L.first;
while(np!=NULL){
outs<<np->data;
np=np->next;
}
return outs;
}
That's because LNode isn't in global scope, it's a nested class of LList. You have to write:
ostream & operator << (ostream & outs, const LList & L){
LList::LNode *np = L.first;
↑↑↑↑↑↑↑
/* rest as before */
}