I am trying to understand how operator overloads works.
I want to code it so that I can write
Log(Log::LEVEL_ERR) << "fatal error: " << 13 ;
And for both the string and the number the overloaded operator is used.
I now have
class Log{
public:
std::ostream& operator<<(char const*);
}
std::ostream& Log::operator<<(char const* text){
if (Log::isToWrite()) {
printLevel();
std::cout << text;
}
return std::cout;
}
This only get's me the string but not the number, why?
Edit
#bitmask Just to be clear, you mean implement like this:
class Log{
public:
friend Log& operator<<(Log& in, char const* text);
}
friend Log& operator<<(Log& in, char const* text){
if (in.isToWrite()) {
in.printLevel();
std::cout << text;
}
return std::cout;
}
Because I get these everywhere now:
error: Semantic Issue: Invalid operands to binary expression ('Log' and 'const char [15]')
Maybe this is really simple but can you spell it out for me?
I'm really not getting it.
Because you returned an ostream&, the next << operator matches operator<<(ostream&, int). You should return *this; (type is Log&) instead, so that the next << operator matches an operator defined for your class.
Related
class String
{
char* array;
public:
String(const char* s)
{
array = new char[strlen(s) + 1]{ '\0' };
strcpy(array, s);
}
~String()
{
if (array)
{
delete[]array;
}
}
String operator+ (const char* p) //返回对象
{
String temp(p);
char* tempStr = temp.array;
temp.array = new char[strlen(array) + strlen(tempStr) + 1]{ '\0' };
strcpy(temp.array, array);
strcat(temp.array, p);
delete[]tempStr;
return temp;
}
friend ostream& operator<<(ostream& output, String& x); // <<函数重载只能定义成友元
};
ostream& operator << (ostream& output, String& x) //对<<重载的方式
{
output << x.array;
return output;
}
int main()
{
String string1("mystring");
cout << string1 + "ab" << endl;
cout << string1 << endl;
return 0;
}
This is my first time asking a question here, so please forgive me if there are any bad descriptions :)
Back to the point ,I have overloaded + and << operators,so I want to get the output "mystringab" by cout<<string1+"ab"<<endl,but the output is garbled.
I think there may be a problem with the + operator overloaded function,can someone please tell me where is the problem?
And if I want to get the correct result, how should I rewrite the overloaded function?
The problem is that the second parameter to overloaded operator<< cannot be bound to an String rvalue since the second parameter is an lvalue reference to a non-const String.
how should I rewrite the overloaded function?
You need to make the second parameter to overloaded operator<< a const String& so that it can work with the second argument "ab" as well, as shown below:
//---------------------------------------- vvvvv------------>low-level const added here
friend ostream& operator<<(ostream& output,const String& x);
Similarly do the same in the definition:
//----------------------------------- vvvvv------------>low-level const added here
ostream& operator << (ostream& output,const String& x)
{
output << x.array;
return output;
}
Also, make sure that your program don't have any undefined behavior. For example, by making sure that you use delete or delete[] only when it is safe to do so(that data to which the pointer points is no longer needed). You can use tools such as valgrind to detect some basic problems.
I have learnt the operator<< can be overloaded by making it a friend function of class.
For example,
struct Test
{
std::string d_data;
Test(const std::string & data) : d_data{data} {}
friend std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
ostr << obj.d_data << '\n';
return ostr;
}
};
int main()
{
Test t1("one");
std::cout << t1;
Test t2("two");
std::cout << t2;
}
one
two
This seems to work as expected.
But, I'm unable to understand why the same isn't working for a global overload.
#include <iostream>
#include <ostream>
#include <string>
std::ostream & operator<<(std::ostream & os, const std::string & s)
{
os << s << '\n';
return os;
}
int main()
{
std::cout << "stackoverflow";
std::cout << "stackoverflow";
}
stackoverflowstackoverflow
Expected the strings to be separated by a newline, but didn't work as expected.
Your operator using
std::cout << "stackoverflow";
requires a user-defined conversion from an object of the type const char * (after the implicit conversion of the string literal to pointer to its first character) to an object of the type std::string.
However the standard basic_ostream class has already an operator that does not require such a conversion
template<class charT, class traits>
basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&, const char*);
So this operator is called instead of your operator.
Moreover within your operator
std::ostream & operator<<(std::ostream & os, const std::string & s)
{
os << s << '\n';
return os;
}
there is recursive calls of itself.
Your could define your operator the following way
#include <iostream>
#include <string>
std::ostream & operator<<(std::ostream & os, const char *s)
{
return std::operator <<( os, s ) << '\n';
}
int main()
{
std::cout << "stackoverflow";
std::cout << "stackoverflow";
}
and get the expected result
stackoverflow
stackoverflow
Note that "stackoverflow" is of type const char[], but not std::string. That means your overload won't be invoked, but the one from standard library (operator<<(std::basic_ostream) is invoked, because it's an exact match and doesn't require the implicit conversion from const char[] to std::string.
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
BTW: It could be found because of ADL.
You can overload globally, but "stackoverflow" is not a std::string, so yours isn't used.
(And there already is such an overload in the standard library.)
To see that it works, move your first overload out of the class definition and make it a non-friend.
The only reason it has to be declared friend is that you have declared it inside the class definition, so it would be a member function otherwise.
This will work as you expect:
struct Test
{
std::string d_data;
Test(const std::string & data) : d_data{data} {}
};
std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
ostr << obj.d_data << '\n';
return ostr;
}
int main()
{
Test t1("one");
std::cout << t1;
Test t2("two");
std::cout << t2;
}
I tried to create simple class and to overload some of it's operators, however, i failed at the very beginning, here's my code:
#include <iostream>
class Person
{
char *firstName;
char *lastName;
int age;
friend std::ostream &operator<<(std::ostream &, const Person &);
public:
Person() : firstName("Piotr"), lastName("Tchaikovsky"), age(10) {}
Person(char* f, char* l, int a)
{
this->firstName = f;
this->lastName = l;
age = a;
}
std::ostream &operator<<(std::ostream& out, const Person &p)
{
out << p.firstName << " " << p.lastName;
return out;
}
};
int main()
{
Person a;
getchar();
getchar();
}
So, before i created this operator overloading function i used debugger to see if constructor is going to work, and it worked, since default values were given correctly to the variable a i created, after that, all i did was that i created function that overloads the operator << and it is a friend function of my class, since i am taught that it is a good thing to do due to the type of the first parameter of overloading function, however, when i try to run this (NOTE: i have not tried to print out anything yet, i wanted to check if everything works fine first) it gives me errors saying:
"too many parameters for this operator function",
"binary 'operator <<' has too many parameters" and
" 'Person::operator<<' :error in function declaration; skipping function body"
however, i can't find any problems with function declaration, and i cannot possibly see how two parameters can be too many for this function. Any help appreciated!
You declare the friend function as a global non-member function. Then you define a member function.
Move the definition of the operator<< function to outside the class:
class Person
{
...
friend std::ostream &operator<<(std::ostream &, const Person &);
...
};
std::ostream &operator<<(std::ostream& out, const Person &p)
{
out << p.firstName << " " << p.lastName;
return out;
}
Or alternatively define the friend function inline:
class Person
{
...
friend std::ostream &operator<<(std::ostream &, const Person &)
{
out << p.firstName << " " << p.lastName;
return out;
}
...
};
Given a class
class ostreamWrapper
{
private:
ostream * str;
public:
ostreamWrapper operator << (const char *);
}
where ostream * str will point to std::cout and ostreamWrapper operator << (const char *) sends the given text to the wrapped ostream str.
In this case, I can only instance << "const char * text" and no other printable data. Unlike directly <<ing a std::cout or std::cerr.
How can the operator method be implemented so it accepts any type of data just as std::cout or std::cerr directly do?
First, write a public operator<< template so it can accept any type and simply forward it to the wrapped ostream.
template <class T>
ostreamWrapper& operator<<(T&& x) {
*str << std::forward<T>(x);
return *this;
}
Second, in order to accept insertion of stream manipulator templates such as std::endl, add a second public operator<< that specifically accepts manipulators intended for the wrapped ostream:
ostreamWrapper& operator<<(ostream& (*manip)(ostream&)) {
*str << manip;
return *this;
}
Omitting the second overload will cause insertion of overloaded manipulators or manipulator templates to fail with "ambiguous overload" or similar error messages.
See an example of the proposed implementation, it would deduce the template parameter type and print accordingly, if you could use C++11 see #Brian answer:
#include <iostream>
using namespace std;
class ostreamWrapper {
private:
ostream* str;
public:
ostreamWrapper(ostream* str_v) : str(str_v) {}
template <typename T>
ostreamWrapper& operator<<(const T& t) {
if (str)
*str << t;
return *this;
}
};
int main() {
ostreamWrapper osw(&std::cout);
osw << 1 << " texto " << std::string(" otro texto ") << 1.2345;
return 0;
}
I am trying to create my own std::string wrapper to extend its functionality.
But I got a problem when declaring the << operator.
Here's my code so far:
my custom string class:
class MyCustomString : private std::string
{
public:
std::string data;
MyCustomString() { data.assign(""); }
MyCustomString(char *value) { data.assign(value); }
void Assign(char *value) { data.assign(value); }
// ...other useful functions
std::string & operator << (const MyCustomString &src) { return this->data; }
};
the main program:
int main()
{
MyCustomString mystring("Hello");
std::cout << mystring; // error C2243: 'type cast' : conversion from 'MyCustomString *' to 'const std::basic_string<_Elem,_Traits,_Ax> &' exists, but is inaccessible
return 0;
}
I wanted cout to treat the class as a std::string, so that I won't need to do something like:
std::cout << mystring.data;
Any kind of help would be appreciated!
Thanks.
Just fyi: my IDE is Microsoft Visual C++ 2008 Express Edition.
If you look at how all stream operators are declared they are of the form:
ostream& operator<<(ostream& out, const someType& val );
Essentially you want your overloaded function to actually do the output operation and then return the new updated stream operator. What I would suggest doing is the following, note that this is a global function, not a member of your class:
ostream& operator<< (ostream& out, const MyCustomString& str )
{
return out << str.data;
}
Note that if your 'data' object was private, which basic OOP says it probably should, you can declare the above operator internally as a 'friend' function. This will allow it to access the private data variable.
You need a free-standing function (friend of your class, if you make your data private as you probably should!)
inline std::ostream & operator<<(std::ostream &o, const MyCustomString&& d)
{
return o << d.data;
}
Firstly, you seem to have an issue with the definition of MyCustomString. It inherits privately from std::string as well as containing an instance of std::string itself. I'd remove one or the other.
Assuming you are implementing a new string class and you want to be able to output it using std::cout, you'll need a cast operator to return the string data which std::cout expects:
operator const char *()
{
return this->data.c_str();
}
That's not how you overload the << operator. You need to pass in a reference to an ostream and return one (so you can stack multiple <<, like std::cout << lol << lol2).
ostream& operator << (ostream& os, const MyCustomString& s);
Then just do this:
ostream& operator << (ostream& os, const MyCustomString& s)
{
return os << s.data;
}