Weird characters appear in ostream in C++ - c++

I have a program that should emulate a simple filesystem, I want to print the structure of directories, so I have overloaded the << operator, and called another function that goes through my structure in rectursion. It works, BUT there are some weird hex values before some of the lines in the output. Is there something wrong with the way I manipulate iwth the ostream ? (I did not include the class definition, but it shouldnt matter)
Thanks all, for any answers!
std::ostream& printTree(std::ostream& os, const CFileSystem::TDir* x, int nmbTabs)
{
int k;
const CFileSystem::TDir * nxt = x;
//cout << pocetTabu<<endl;
while(nxt){
os<<"--";
for(k=0;k<nmbTabs;k++){
os << '\t' ;
}
os<<"--";
os << nxt->m_Name << endl;
if(nxt->m_Sub){
os << printTree(os,nxt->m_Sub,nmbTabs+1);
}
nxt=nxt->m_Next;
}
return os;
}
std::ostream& operator <<(std::ostream& os, const CFileSystem& x)
{
os << "/" << endl;
os << printTree(os, x.m_Root,1);
return ( os );
}

os << printTree(os, x.m_Root,1);
What is this? printTree returns std::ostream &, and you're trying to output that (an ostream)?
That should be this:
printTree(os, x.m_Root,1);
That means, your operator<< should be implemented as:
std::ostream& operator<<( std::ostream & os, const CFileSystem & x)
{
os << "/" << std::endl;
return printTree(os, x.m_Root,1);
}

Related

Operator << overwrite with std::ostringstream issue [duplicate]

This question already has an answer here:
C++ std::stringstream operator<< overloading
(1 answer)
Closed 3 years ago.
Here's my toy program. It fails to compile with error message " no operator << matches these operands". Any help will be appreciated.
struct foo {
std::string name;
};
std::ostringstream& operator<<(std::ostringstream& os, const foo& info)
{
os << info.name;
return os;
}
void insert(const foo& info)
{
std::ostringstream os;
os << "Inserted here " << info; // don't work here
}
int main()
{
foo f1;
f1.name = "Hello";
insert(f1);
}
The reason
os << "Inserted here " << info;
does not work is
os << "Inserted here "
returns a std::ostream&, not a std::ostringstream&.
Options:
Change your function to be use std::ostream instead of std::ostringstream.
std::ostream& operator<<(std::ostream& os, const foo& info) { ... }
Change how you use it. Use
os << "Inserted here ";
os << info;
I strongly recommend using the first option.

Overloading output (<<) operator for a class with private enum member [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm having a hard time trying to overload my << output operator for this class. The class has private members - enum class and string. The code I made compiles and runs, but the << operator is overloaded only for the enum class.
From what I understand and read about it, I need to make something like this:
friend ostream& operator<<(ostream& os, CDirectory const& dir)
but I seem to fail at implementing it and at this point I really have no ideas. I want to overload the operator for the whole class CDirectory and not only the enum class Filetype, that is one of the members. Is this even possible to do?
class CDirectory {
string m_strDirectory;
enum class Filetype {
Archive, Hidden, ReadOnly, System, FileNotSupported
};
multimap <CFile, Filetype> m_DirectoryMap;
public:
/* overloading operator<< for the enum class Filetype */
friend ostream& operator<<(ostream& os, Filetype const type)
{
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
return os;
}
/* explicit constructor - reads data from a file and inserts pairs
of types pair <CFile, enum Filetype> in a multimap */
CDirectory (const string& n) {
fp.open (n, ios::in);
string dirName, fileName, fType;
int fileSize;
Filetype filetype;
fp >> dirName;
m_strDirectory = dirName;
while (fp >> fileName >> fileSize >> fType) {
CFile obj (fileName, fileSize);
if (fType == "Archive")
filetype = Filetype::Archive;
else if (fType == "Hidden")
filetype = Filetype::Hidden;
else if (fType == "ReadOnly")
filetype = Filetype::ReadOnly;
else if (fType == "System")
filetype = Filetype::System;
else
filetype = Filetype::FileNotSupported;
m_DirectoryMap.insert(pair<CFile, Filetype>(CFile(obj.getFileName(), obj.getFileSize()), Filetype(filetype)));
}
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () {
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
};
UPDATE:
I tried the following code, for implementing the overload operator << for my entire class, but it produces an error - error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'|on these lines (1 of them is in my constructor and 1 in my printMap function) - cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
I'm guessing that it has something to do with the p->second part, but I don't know what exactly is going on. Any thoughts on it?
Update: yep, the problem is when I try to print out the enum with p->second. If I remove that part it compiles..
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
const Filetype& type;
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
os << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
I assume in the end you want to be able to do something like this:
CDirectory dir("input_file");
std::cout << dir;
and this should output everything at once (basically everything that CDirectory::printMap() currently prints, right?
For this to work, you need to overload operator<< for your CDirectory class as a non-member function:
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
std::cout << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
and then make this function a friend of your class:
friend std::ostream& operator<<(std::ostream &os, const CDirectory &dir);
for it to be able to access the class's private members.
Alternatively, because you already have a print function in your class, you can just forward to that one so you don't need to make operator<< a friend (some people frown on friend functions). For this to work, you have to change your printMap() function a bit:
void printMap (std::ostream &os) const
{
auto p = m_DirectoryMap.begin();
os << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
dir.printMap();
return os;
}
Once you have this operator, written in either of the two variants, in your main() function you can write:
CDirectory dir("input_file");
std::cout << dir;
Two notes regarding the operator that you already overloaded for Filetype. It is the only other operator that is necessary to be overloaded for your class to be streamable (operator<< is already overloaded for std::string and integer types, so you don't have to do it to be able to write strings and numbers). Also keep in mind that, even though you wrote it inside your class, it is not actually a member function and can't be a member function (why?). You were able to define it there because you declared it friend, but the usual way of defining friend functions is this:
class A {
...
friend void f();
...
};
void f() {
...
}
I have the impression that you are confused between data members of your class and nested types (member types). Operators are (to be) defined for types, not data members.
You have to overload the operator<< (for stream output) for every class/type for which you want to use it and for which it is not already defined. From your code, I reckon that you only need to overload
ostream& operator<<(ostream& os, Filetype const type)
which you did. So it is unclear what precisely your problem is and what it symptoms are.
It seems to me you have everything you need, you just need to put it together.
printMap() function already prints everything in your class CDirectory. It prints everything to cout. So you could just do the following and it should work.
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap();
}
However this code is not well written since the opeartor<< is more general and not just made for cout. To make it better you could rewrite your printMap() function to be take a reference to ostream to which you want to output.
void printMap (ostream& os)
{
os << m_strDirectory << endl;
auto p = m_DirectoryMap.begin();
while ( p != m_DirectoryMap.end())
{
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () { printMap(std::cout); }
Now the operator would look like this:
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap(os);
}
I hope this better explains what is going on.

Outputing a list separated by space

I'm overloading operator << to output my container separated by space:
std::ostream& operator<< (std::ostream &os, const MyContainer &v)
{
os << "[";
for (const auto &i : v) {
os << i << " ";
}
os << "\b]"; // <--
return os;
}
MyContainer c{1,2,3};
std::cout<<c<<std::endl;
I'm using '\b' to avoid the extra space at the end of the list, it works fine with above code.
But it might not be a good idea, does '\b' work well with other types of ostream? Any other idea to output data like this?
But it might not be a good idea, does '\b' work well with other types of ostream?
You are absolutely right about this not being a good idea: '\b' works fine in console mode, but it does not play well with other streams, such as files.
A better approach is to not output the extra space in the first place:
std::ostream& operator<< (std::ostream &os, const MyContainer &v)
{
os << "[";
auto first = true;
for (const auto &i : v) {
if (!first) {
os << " ";
} else {
first = false;
}
os << i;
}
os << "]";
return os;
}
A simple pragmatic solution is to just add a space before the range loop:
std::ostream& operator<< (std::ostream &os, const MyContainer &v)
{
os << "[ "; // <--
for (const auto &i : v) {
os << i << " ";
}
os << "]";
return os;
}
MyContainer c{1,2,3};
std::cout<<c<<std::endl;
The result is a slightly different output, but still achieves the presumed goal of visually pleasing symmetrical formatting: instead of [1 2 3] you get [ 1 2 3 ]. Empty lists will print as [ ].

setw within a function to return an ostream

here is my function
ostream margain(std::string firstWord)
{
ostream x;
x << std::setw(20) << firstWord;
return x;
}
in main I want to use the function as follow
std::cout<< margain("start") << "````````````````````````````````````" << std::endl;
// print things out
//then
std::cout<< margain("End") << "````````````````````````````````````" << std::endl;
I get the output, start or end is not shown, and the return value is
0````````````````````````````````````
how can I fix it? and why?
Edit:
I know that the function is what causing that, because if I add this
cout << std::setw(20) << firstWord;
in the function, It prints right,
I fixed it, not the best way, but as
calling the function as
margain(std::cout, "End") <<
"~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~" << endl;
the function looks like
ostream& margain(ostream& stream, std::string firstWord)
{
stream << std::left << std::setw(10) << firstWord;
return stream;
}
anyone know better way?
You are printing the value of the ostream, not value of firstword. The ostream x in this case is an unopened stream, so it doesn't "do" anything. Because the compiler allows to conversion to either bool (C++11) or void * (before C++11), the "value" from that conversion is printed. Note that any operations on x will not affect cout.
The easiest solution, I would think is to actually add std::setw(20) to your output line:
std::cout<< std::setw(20 << "End" << "````````````````````````````````````" << std::endl;
The other choice would be to pass the std::cout to margain, and return the std::string, something like this:
std::string margain(ostream& x, const std::string& firstWord)
{
x << std::setw(20);
return firstWord;
}
then you could do:
std::cout<< margain(cout, "start") << "````````````````````````````````````" << std::endl;
But it's not exactly flexible or "neat".
The third option is of course to have a MarginString class:
class MarignString
{
private:
int margin;
std::string str;
public:
MarginString(int margin, std::string str) margin(margin), str(str) {}
operator std::string() { return str; }
friend std::ostream& operator(std::ostream& os, const MarginString& ms);
};
std::ostream& operator(std::ostream& os, const MarginString& ms)
{
os << std::setw(ms.margin) << ms.str;
return os;
}
...
std::cout<< MarginString(20, "start") << "````````````````````````````````````" << std::endl;
Note that this last way is probably not that great either... ;)
struct margin
{
margin(std::string word) : word(word) { }
friend std::ostream& operator <<(std::ostream& os, margin const& m)
{
return os << std::setw(20) << m.word;
}
private:
std::string word;
};

error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'

Getting this error and I'm pretty sure it's in the operator<< function. Both prints are public.
void CRational::print() const
{
print(cout);
}
void CRational::print(ostream & sout) const
{
if(m_denominator == 1)
cout << m_numerator;
else
cout << m_numerator << "/" << m_denominator;
}
ostream operator<<(ostream & sout,const CRational a)
{
a.print();
return sout;
}
CRational operator++() // prefix ++x
{
m_numerator += m_denominator;
return *this;
}
in main:
cout << "e before: " << e << ", \"cout << ++e\" : " << ++e << " after: " << e << endl;
You need to return the ostream by reference, not value. Its trying to call a constructor.
Might as well pass 'a' as reference as well:
ostream& operator<<(ostream & sout,const CRational& a)
I also note that the print method is probably wrong. It has sout passed as the name of the stream but is then implemented using cout directly. It should be
void CRational::print(ostream & sout) const
{
if(m_denominator == 1)
sout << m_numerator;
else
sout << m_numerator << "/" << m_denominator;
}
ostream operator<<(ostream & sout,const CRational a)
^ You are trying to return by value
Streams are not copyable, so you can't return one by value. You need to return the stream by reference (std::ostream&).
Also, you should probably be outputting to sout in your CRational::print(ostream&) function (otherwise, why take it as an argument?) and you should probably be passing sout when you call a.print() in your operator<< overload (otherwise, the overload doesn't really do what an idiomatic operator<< overload for a stream is supposed to do).
operator<< should return a reference to an ostream: ostream& operator<<...
Also your functions are kinda messed up. Instead of using cout, you should used the passed in ostream which you've named sout.