I was trying to write some operator overload functions, especially the << operator to use it with a custom class and an std::ofstream object, but I was a bit confused by the syntax used in various examples found online. For example, let's consider the operator<< overload as a non-member function for a simple custom class:
#include <fstream>
class Example {
public:
int first;
int second;
};
// I found this kind of operator on the Internet
std::ofstream& operator<< (std::ofstream& out, Example obj) {
out << obj.first << endl << obj.second;
return out;
}
int main() {
Example a={1,2};
std::ofstream out;
out.open("test");
out << a;
out.close();
}
I don't really get why It should return std::ofstream& to work properly. I tried using the following operator
void operator<< (std::ofstream& out, Example obj) {
out << obj.first << endl << obj.second << endl;
}
and it worked as well. I mean, can't out << obj; be interpreted as operator<< (out , obj); ? Why does it have to return something since I'm passing a reference to the std::ofstream object?
The same doubt arose when I was trying to write an operator= overload as a member function for a custom class, as the simple example that follows
class Custom{
public:
int up;
int down;
Custom& operator= (Custom a) {
up=a.up;
down=a.down;
return *this;
}
};
I used the copy-swap idiom for the assignment operator, so don't mind the operator definition too much, it's just an example. Again, writing
Custom obj1, obj2;
obj1 = obj2;
since I can interpret obj1 = obj2; as obj1.operator=(obj2), why is the return type Custom& required instead of void?
If you want to be able to chain operator<<s together, you have to use a return type (better std::ostream& than std::ofstream&, so you can use it for std::cout and like, too).
out << a << b;
(out << a) << b;
^^^^^^^^^^
lhs has to be a stream
For assignment operator, the reason is essentially the same. C++ syntax allows you to write many expressions requiring the return type, for example this:
Custom obj1, obj2, obj3;
(obj1 = obj2) + obj3 ... // assign obj2 to obj1 and work with that...
Returning a reference allows you to chain the operators, like
std::cout << e1 << e2;
Return a reference instead of void, make it possible to write like
out << obj1 << obj2 << obj3;
For operator=, you can write
obj1=obj2=obj3;
You can write somthing like cout << "First operand" << "Second operand" because first operand returns reference to ostream and second operand works with this reference.
operator= works same way. You can write a = b = c, but also you can put it inside if (a = b) or while (a = b). This can make your code shorter, but is a little dangerous.
Related
Sorry for the not clear title.
Recently I started to learn C++ and I don't know how to overload operator << to make it repeatable.
Here's an example code.
class Foo{
private:
int* a;
int idx = 0;
public:
Foo(){a = new int[100];
void operator<< (int a) {arr[idx++] = a;}
What << does is basically class get integer number as an operand and save it into arr.(Ignore overflow case here)
For example, a << 100 will add 100 into array.
What I want to do is make << operator can be repeatedly used inline like a << 100 << 200
How should I fix above code to allow this function?
Thanks in advance :)
The overloaded Foo::operator<<() takes actually two arguments:
The parameter int given as right-hand side
The implicit this from left-hand side.
To allow chaining of this operator, it should return a reference to the left-hand-side (i.e. *this) to become usable at left-hand-side itself.
Sample code:
#include <iostream>
struct Foo {
Foo& operator<<(int a)
{
std::cout << ' ' << a;
return *this;
}
};
int main()
{
Foo foo;
foo << 1 << 2 << 3;
}
Output:
1 2 3
Live demo on coliru
Chaining is enabled by returning a reference to the instance so you can call another method:
class Foo{
private:
std::vector<int> a;
public:
Foo(){}
Foo& operator<< (int a) {
arr.push_back(a);
return *this;
}
};
Now you can call f << 100 << 200 << 42;.
Note that I replaced the array with a std::vector to make Foo less broken (unless you have a descrutor that you did not show it was leaking memory, you could fix that, but then still copying would cause problems, in short you need to respect the rule of 3/5 when you own a resource, using a std::vector makes things much simpler).
PS: Same works for other methods. You simply call another method on the returned reference to this. Note that operators are just methods (with some syntactic sugar) and to see that you can write as well f.operator<<(100).operator<<(200).operator<<(42);.
Return a reference to *this. It's unrelated but you should use a vector to avoid memory leaks. Try to avoid raw new
class Foo{
private:
std::vector<int> a;
public:
Foo &operator<< (int a) {
arr.push_back(a);
return *this;
}
};
I want to have double values with a name and units, but I want to use them as if they were simple doubles. For example I want to use them like this:
int main(){
NamedValue a("a","m");
NamedValue b("b","m");
NamedValue c("c","m^2");
a = 3;
b = 5;
c = a*b;
std::cout << a << b << c << std::endl;
return 0;
}
and the output should be:
a = 3 m
b = 5 m
c = 15 m^2
I came up with this solution:
class NamedValue {
public:
NamedValue(std::string n,std::string u) : name(n),units(u){}
const std::string name;
const std::string units;
void operator=(double v){this->value = v;}
void operator=(const NamedValue& v){this->value = v.value;}
operator double() const { return value; }
private:
double value;
};
std::ostream& operator<<(std::ostream& stream,const NamedValue& v) {
stream << v.name << " = " << (double)v << " " << v.units << std::endl;
return stream;
}
Unitl now it works nicely, but I am mainly concerned about the assignment operator void operator=(const NamedValue& v){this->value = v.value;} that is not exactly doing, what one normally would expect of an assignment operator.
Are there any bad consequences that I will face?
I am thinking about things like passing an object as parameter and stuff like that. However, a function like this
NamedValue test(NamedValue x){return x;}
works without problems, as there is no assignment involved (only copy constructor). Am I missing something? Is there anything else I should be aware of?
ps: Just in case you wonder, at the moment I do not care about checking the units when doing calculations.
The assignment operator is totally fine. The only thing unusual about it is that you did not return the object so the operator calls cannot be chained. Otherwise, it's a completely normal operator.
I'd like to know how do stream classes work in C++. When you say:
cout<<"Hello\n";
What does exactly do "<<". I know that cout is an object form iostream that represents the standard output stream oriented to narrow characters (char).
In C "<<" is the bitwise shift operator so it moves bits to the left but in C++ it's and insertion operator. Well, that's all I know, I don't really understand how does this work under the hood.
What I'm asking for is detailed explanation about stream classes in C++, how they are defined and implemented.
Thank you very much for your time and sorry for my English.
Let's create a class that looks like cout (but without as many bells and whistles).
#include <string>
class os_t {
public:
os_t & operator<<(std::string const & s) {
printf("%s", s.c_str());
return *this;
}
};
int main() {
os_t os;
os << "hello\n";
os << "chaining " << "works too." << "\n";
}
Notes:
operator<< is an operator overload just like operator+ or all of the other operators.
Chaining works because we return ourselves: return *this;.
What if you can't change the os_t class because someone else wrote it?
We don't have to use member functions to define this functionality. We can also use free functions. Let's show that as well:
#include <string>
class os_t {
public:
os_t & operator<<(std::string const & s) {
printf("%s", s.c_str());
return *this;
}
};
os_t & operator<<(os_t & os, int x) {
printf("%d", x);
return os;
// We could also have used the class's functionality to do this:
// os << std::to_string(x);
// return os;
}
int main() {
os_t os;
os << "now we can also print integers: " << 3 << "\n";
}
Where else is operator overloading useful?
A great example of how this kind of logic is useful can be found in the GMP library. This library is designed to allow arbitrarily large integers. We do this, by using a custom class. Here's an example of it's use. Note that operator overloading let's us write code that looks almost identical to if we were using the traditional int type.
#include <iostream>
#include <gmpxx.h>
int main() {
mpz_class x("7612058254738945");
mpz_class y("9263591128439081");
x = x + y * y;
y = x << 2;
std::cout << x + y << std::endl;
}
<< is a binary operator in C++, and thus can be overloaded.
You know of the C usage of this operator, where 1 << 3 is a binary operation returning 8. You could think of this as the method int operator<<(int, int) where passing in arguments 1 and 3 returns 8.
Technically, operator<< could do anything. It's just an arbitrary method call.
By convention in C++, the << operator is used for handling streams in addition to being the bit-shift operator. When you perform cout << "Hello!", you are calling a method with prototype ostream & operator<< (ostream & output, char const * stream_me). Note the return value ostream &. That return allows you to call the method multiple times, like std::cout << "Hello World" << "!"; which is calling operator<< twice... once on std::cout and "Hello World", and the second time on the result of that first invocation and "!".
In general, if you were to create a class named class Foo, and you wanted it to be printable, you could define your printing method as ostream & operator<< (ostream & output, Foo const & print_me). Here is a simple example.
#include <iostream>
struct Circle {
float x, y;
float radius;
};
std::ostream & operator<< (std::ostream & output, Circle const & print_me) {
output << "A circle at (" << print_me.x << ", " << print_me.y << ") with radius " << print_me.radius << ".";
}
int main (void) {
Circle my_circle;
my_circle.x = 5;
my_circle.y = 10;
my_circle.radius = 20;
std::cout << my_circle << '\n';
return 0;
}
Operators can be considered functions with syntactic sugar that allow for clean syntax. This is simply a case of operator overloading.
friend ostream &operator<<(ostream &output,
const Distance &D)
{
output << "F : " << D.feet << " I : " << D.inches;
return output;
}
Because you don't want the function that writes a instance to a stream to modify the instance.
And because a const reference, unlike a non-const one (unless you're using MSVC) can accept a temporary object, which is useful.
IMHO: passing by reference is more efficient than passing via copy and the const keyword stops you from altering the original instance...
in c++ why we declare reference parameter as const in overloaded
function?
No, in the function that you've posted it's done so for the reasons mentioned in the other answers, but there's no requirement i.e. the standard doesn't mandate that an overloaded function taking a reference parameter should be const.
You're mixing up multiple things here. Overloading is a language feature where multiple functions with identical names can coexist, while const is a qualifier which says the data wouldn't change in a given context through that variable/function. They've no relationship that ties them saying it has to be a const if the overloading function takes a reference paramater. The same goes for reference variables too; they're just an alias (a different name) of another variable which has nothing to do with const or function overloading.
a function signature is a contract between the calling code and the function code.
You want that the function will require as less demands as possible.
If you write demanding signature like
ostream &operator<<(ostream &output, Distance &D)
then you won't be able to call your operator from code that operates on const objects:
void Foo(const Distance& d) {
cout << d; // syntax error
}
in other words putting as less requirements as possible on function arguments makes your function more general.
It is not obligatory to define a reference parameter as const in overloaded functions. Simply in your example of the operator << the right operand is not changed in the function. This allows to use this operator with const objects.
For example
#include <iostream>
class Distance
{
public:
//...
friend ostream &operator<<(ostream &output,
const Distance &D)
{
output << "F : " << D.feet << " I : " << D.inches;
return output;
}
private:
float feet;
//...
};
int main()
{
const Distance d1;
std::cout << d1 << std:;endl;
}
The compiler would issue an error parsing statement
std::cout << d1 << std::endl;
if the second parameter in the operator << would be declared as a non-const reference.
Another example
#include <iostream>
struct A
{
A() {}
A( A & ) { std::cout << "A( A & )" << std::endl; }
A( const A & ) { std::cout << "A( const A & )" << std::endl; }
};
int main()
{
A a1;
A a2( a1 );
const A a3;
A a4( a3 );
}
In this example there are two copy constructors one of which defines the parameter as non-const reference and the other defines the parameter as const reference.
If there would not be the second copy constructor then the compiler would issue an error parsing statement
A a4( a3 );
Safety: with const we make sure we won't accidentaly modify the object.
Speed: References are much faster than passing by value. Also const tells the compiler the object won't be modified, therefore some optimizations could be made.
I need to overload the << operator for streams to work with built-in types. For strings it's not a problem, since I simply overload the function like this:
ostream& operator<<(ostream& os, const char* str) { /*...*/ }
This works because this function is global, not a member. The problem is that I need to overload the << operator for other primitive types (ints, floats, etc) but those are member functions. Is there a way I can do this? I need it to work with not only cout but other streams as well. Thanks in advance.
You shouldn't try to change what the operator in std::cout << 3; does. It's part of a standard API. If you need to output in some format which stream manipulators can't support, then for example you could write a little wrapper:
struct MyFormatter {
MyFormatter (ostream &o) : o(o) {}
ostream &o;
};
MyFormatter &operator<<(MyFormatter &mf, int i) {
mf.o << "int(" << i << ")"; // or whatever
return mf;
}
Then use it like this:
MyFormatter mf(std::cout);
mf << 1 << "," << 2 << "," << 3;
In C++, operator overloads require at least one operand of a "class type" or enumeration type.
The point is you are not allowed to overload operator for primitive types.
http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.10