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.
Related
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 am trying to read and display the contents of a file named myDocument.txt, but I always get the following error with my header file.
./ReadDocument.h:22:24: error: expected parameter declarator std::ifstream myflux("myDocument.txt");
What's going on?
Here is my ReadDocument.h:
class ReadDocument{
public:
ReadDocument(); //empty constructor
ReadDocument(const std::string& fileName); //constructor
void documentContent();
friend std::ostream& operator <<(std::ostream& os, const ReadDocument& d);
std::list<std::string> myList;
std::ifstream myflux("myDocument.txt");
if(myflux){
//Getting the words from the file string by string
std::string data;
while(myflux>>data){
myList.push_back(data);
}
myflux.close();
}
else{
std::string message = "\t\tERROR ==> This file doesn't exist.";
throw FileDoesntExistException(message);
}
};
Here is my ReadDocument.cpp:
#include "ReadDocument.h"
ReadDocument::ReadDocument(){}
void ReadDocument::documentContent(){}
std::ostream& operator <<(std::ostream& os, const ReadDocument& d){
for(std::list <std::string> :: const_iterator it = ReadDocument::myList.begin(); it!=ReadDocument::myList.end(); it++)
std::cout<<*it<<std::endl;
return os;
}
And this is my UseReadDocument.cpp
#include "ReadDocument.h"
int main(){
ReadDocument rd("test.txt");
std::cout<<rd<<std::endl;
return 0;
}
I tried renamed the file and still the same problem.
I put it in the class, and doesn't change anything.
I always have the same error coming out.
and yes it is my entire code
The part of your class after myflux is not in a method.
Did you want to put the code in the function documentContent, like this?
ReadDocument.h:
class ReadDocument{
public:
ReadDocument(); //empty constructor
ReadDocument(const std::string& fileName); //constructor
void documentContent();
friend std::ostream& operator <<(std::ostream& os, const ReadDocument& d);
std::list<std::string> myList;
std::ifstream myflux("myDocument.txt");
};
ReadDocument.cpp:
#include "ReadDocument.h"
ReadDocument::ReadDocument(){}
void ReadDocument::documentContent(){
if(myflux){
//Getting the words from the file string by string
std::string data;
while(myflux>>data){
myList.push_back(data);
}
myflux.close();
}
else{
std::string message = "\t\tERROR ==> This file doesn't exist.";
throw FileDoesntExistException(message);
}
}
std::ostream& operator <<(std::ostream& os, const ReadDocument& d){
for(std::list <std::string> :: const_iterator it = ReadDocument::myList.begin(); it!=ReadDocument::myList.end(); it++)
std::cout<<*it<<std::endl;
return os;
}
By the way, you should avoid creating an empty constructor and filling it with nothing.
Since C++11 you should write ReadDocument() = default; in your header and remove ReadDocument::ReadDocument(){} from the cpp.
With your class your are declaring two public variables and trying to give each instance of your class these default characteristics. The solution in to put the default conditions in the default constructor as follows:
class ReadDocument{
private:
std::list<std::string> myList; //moved member variables to private
std::ifstream myflux; //part of class
public:
ReadDocument(); //empty constructor
ReadDocument(const std::string& fileName); //constructor
void documentContent();
friend std::ostream& operator <<(std::ostream& os, const ReadDocument& d);
};
Implementation:
#include "ReadDocument.h"
ReadDocument::ReadDocument()
{
myflux.open("myDocument.txt");
if(myflux){
//Getting the words from the file string by string
std::string data;
while(myflux>>data){
myList.push_back(data);
}
myflux.close();
}
else{
std::string message = "\t\tERROR ==> This file doesn't exist.";
throw FileDoesntExistException(message);
}
}
void ReadDocument::documentContent(){}
std::ostream& operator <<(std::ostream& os, const ReadDocument& d){
for(std::list <std::string> :: const_iterator it =
d.myList.begin(); it!=d.myList.end(); it++)
std::cout<<*it<<std::endl;
return os;
}
Code will now associate myflux with "myDocument.txt" and extract the file data into myList by default (unless instantiated with string parameter for use with const string& constructor) for each instance of the ReadDocument class. As well as a few other fixes in the ostream function.
P.S* Assuming this is your entire .cpp file associated with the ReadDocument class, you forgot to implement the constructor containing the const string& parameter, ReadDocument(const std::string& fileName).
Why i still have ERROR: exepected an identifier in std::ofstream << val on the line below? msvc.
std::ostream& operator<< (bool val) { m_lock.lock(); std::ofstream << val; m_lock.unlock(); return *this; }
class OfstreamLog : public std::ofstream {
private:
std::mutex m_lock;
public:
OfstreamLog() : std::ofstream() { }
explicit OfstreamLog(const char* filename, ios_base::openmode mode = ios_base::out) : std::ofstream(filename, mode) { }
std::ostream& operator<< (bool val) { m_lock.lock(); std::ofstream << val; m_lock.unlock(); return *this; }
std::ostream& operator<< (short val);
std::ostream& operator<< (unsigned short val);
std::ostream& operator<< (int val);
std::ostream& operator<< (unsigned int val);
std::ostream& operator<< (long val);
std::ostream& operator<< (unsigned long val);
std::ostream& operator<< (float val);
std::ostream& operator<< (double val);
std::ostream& operator<< (long double val);
std::ostream& operator<< (void* val);
std::ostream& operator<< (std::streambuf* sb);
std::ostream& operator<< (std::ostream& (*pf)(std::ostream&));
std::ostream& operator<< (std::ios& (*pf)(std::ios&));
std::ostream& operator<< (ios_base& (*pf)(ios_base&));
};
std::ofstream is a type name. You can't call a nonstatic method or operator for it without any object.
In this case you probably want std::ofstream::operator<<(val); instead of std::ofstream << val;.
Explanation:
When you want to call method of a parent class from method of a child class, you do it like this:
class A
{
void func() {}
};
class B
{
void test()
{
func(); // Like this
}
};
But if child class have method with same name (more precisely, with same signature (it means, same name and argument types)), it will be called instead of parent's one. To explicitly call the method of the parent class, you can use this syntax:
class A {...};
class B
{
void test()
{
A::func(); // Notice `A::`
}
};
Now let's talk about operators. When you want to call an operator, you usually use an object name for it, like object << 10;. But when you want to call operator of a class (or it's parent) from a method of this class, you should use full operator syntax:
class A
{
operator<<(int){}
};
class B
{
void test()
{
operator<<(10); // <-----
*this << 10; // Also you can do it like this
}
};
Now, we combine these two techniques:
If child class have operator with same signature as parent's one and you want to call operator of the parent, you do it like this:
class A {...};
class B
{
void test()
{
A::operator<<(10); // Notice `A::`
*(A*)this << 10; // Also you can do it like this
}
};
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.
This prints an error message about qualifiers but don't really understand what that means and how to adjust the code for it to work? Anyways, thanks a lot for looking at the code.
Note: The ostream operator is friended in the Node class.
using namespace std;
ostream& operator(ostream& output, const Node* currentNode)
{
return output;
}
void Node::nodeFunction()
{
//This node has items attached to the 'this' statement. After
//the necessary functions, this is called to output the items.
cout << this;
}
Your overloaded stream operator declaration should be like this:
std::ostream& operator<<(std::ostream& os, const T& obj);
^^^^^^^^^^^^^
You should be returning a reference to object of std::ostream, the & is wrongly placed in your overloaded function prototype.
Have a look at the working sample here.
Adding the source code here, for completeness.
Note: I have taken class Node members as public for ease of demonstration.
#include<iostream>
using namespace std;
class Node
{
public:
int i;
int j;
void nodeFunction();
friend ostream& operator <<(ostream& output, const Node* currentNode);
};
ostream& operator<<(ostream& output, const Node* currentNode)
{
output<< currentNode->i;
output<< currentNode->j;
return output;
}
void Node::nodeFunction()
{
//This node has items attached to the 'this' statement. After
//the necessary functions, this is called to output the items.
cout << this;
}
int main()
{
Node obj;
obj.i = 10;
obj.j = 20;
obj.nodeFunction();
return 0;
}
The & on the return value of the operator is in the wrong place, and it's generally better to use references rather than pointers for ostream operators:
ostream& operator<<(ostream &output, const Node ¤tNode)
{
// Output values here.
return output;
}
void Node::nodeFunction()
{
cout << *this;
}