toString() kind of implementation in C++14 [duplicate] - c++

This question already has answers here:
Why we need to return reference to istream/ostream while overloading >> and << operators?
(4 answers)
Closed 4 years ago.
class Fruit
{
private:
std::string m_name;
std::string m_color;
public:
Fruit(std::string name, std::string color)
: m_name(name), m_color(color)
{
}
std::string getName() const { return m_name; }
std::string getColor() const { return m_color; }
};
class Apple : public Fruit
{
private:
double m_fiber;
public:
Apple(std::string name, std::string color, double fiber)
:Fruit(name, color), m_fiber(fiber)
{
}
double getFiber() const { return m_fiber; }
friend std::ostream& operator<<(std::ostream &out, const Apple &a)
{
out << "Apple (" << a.getName() << ", " << a.getColor() << ", " << a.getFiber() << ")\n";
return out;
}
};
My question is regarding the friend function with the overloaded operator '<<'.
I need to understand some basics which are troubling me, for one why does the function return a reference to a stream ?

The returned lvalue ref to the stream means that you can reuse the returned value as an lvalue which references the returned object so you can chain multiple insertion operations together. For example,
std::cout << Apple("foo", "red", 3.4) << Apple("bar", "red", 5.5);
or perhaps better seen in terms of precedence as
(std::cout << Apple("foo", "red", 3.4)) << Apple("bar", "red", 5.5);
as opposed to, if you didn't return an lvalue ref, and perhaps just returned void, only the following would work:
std::cout << Apple("foo", "red", 3.4)
If you just returned std::ostream instead of std::ostream&, then an attempt to copy of the stream object would be attempted, and fail at compilation b.c. the copy ctor is deleted as shown here http://www.cplusplus.com/reference/ostream/ostream/ostream/.

Related

How do I properly overload the << operand to produce the desired results?

https://leetcode.com/explore/learn/card/fun-with-arrays/521/introduction/3294/
I'm following this Leetcode course on Arrays and am trying to follow along using C++ as they use Java, but I'm struggling to get past this part. I just want to read items from the pokedex array I made.
The initial error I got was:
No operator << matches these operands.
Array.cpp(16,15) operand types are std::ostream << Pokemon
I then tried to overload the << operator as I've seen other people ask on here, but I'm not getting the output I want. When I compile the program as-is, nothing prints.
Can someone explain what I can do to get the desired output?
Cyndaquill is a fire type at level 5
Also, can someone explain, or point me in the direction of someone who can explain, operator overloading in an easy non-verbose way? A lot of what I've seen on StackOverflow has been overly verbose and confusing. Maybe it's because I'm new to C++, but still.
Array.cpp
#include <iostream>
#include "Array_Header.hpp"
int main() {
Pokemon pokeDex[15];
Pokemon Cyndaquill = Pokemon("Cyndaquill", 5, "Fire");
Pokemon Totodile = Pokemon("Totodile", 5, "Water");
Pokemon Chikorita = Pokemon("Chikorita", 5, "Grass");
pokeDex[0] = Cyndaquill;
pokeDex[1] = Totodile;
pokeDex[2] = Chikorita;
std::cout << pokeDex[0];
std::cout << pokeDex[1];
std::cout << pokeDex[2];
std::cout << pokeDex[3];
}
Array_Header.hpp
#include <string>
class Pokemon {
public:
//variable declarations
std::string name;
int level;
std::string type;
//Constructor for the DVD class
Pokemon(std::string name, int level, std::string type);
Pokemon() = default;
//toString function declaration
std::string toString();
friend std::ostream& operator<<(std::ostream& os, const Pokemon& obj)
{
return os;
};
};
Array_Header.cpp
#include "Array_Header.hpp"
//Constructor Definition
Pokemon::Pokemon(std::string name, int level, std::string type){
this->type = type;
this->level = level;
this->name = name;
};
//toString function definition
std::string Pokemon::toString(){
return this->name + " is a " + this->type + " type at level " + std::to_string(level) + "\n";
};
Your operator overload for << to print to an std::ostream an object of type Pokemon does nothing but return the os parameter. You need to add the logic for printing inside of here, which would look something like this:
friend std::ostream& operator<<(std::ostream& os, const Pokemon& obj)
{
os << obj.toString();
return os;
};

Error with << operator overload returning a std::string

I'm having troubles understanding the reason why the compiler accuses error, when the return type of a << operator overload is std::string. Could you please help me understand?
Bellow is an reproducible example, which gives a gigantic error.
class XY
{
int X__;
int Y__;
public:
XY(int x, int y):X__(x), Y__(y){}
~XY(){}
std::string operator<<(const XY_cartesiano& c)
{
std::stringstream ss;
ss << "{ " << X__ << ", " << Y__ << " }";
return ss.str();
}
int x() const{return X__;}
int y() const{return Y__;}
};
void main()
{
XY a(1,2);
std::cout << a;
}
Let's take something like this as an example:
cout << "My number is " << 137 << " and I like it a lot." << endl;
This gets parsed as
((((cout << "My number is ") << 137) << " and I like it a lot.") << endl);
In particular, notice that the expression cout << "My number is " has to evaluate to something so that when we then try inserting 137 with << 137 the meaning is "take 137 and send it to cout."
Imagine if cout << "My number is " were to return a string. In that case, the << 137 bit would try to use the << operator between a string on the left-hand side and an int on the right-hand side, which isn't well-defined in C++.
The convention is to have the stream insertion operator operator << return a reference to whatever the left-hand side stream is so that these operations chain well. That way, the thing on the left-hand side of << 137 ends up being cout itself, so the above code ends up essentially being a series of chained calls to insert things into cout. The signature of these functions therefore usually look like this:
ostream& operator<< (ostream& out, const ObjectType& myObject) {
// ... do something to insert myObject into out ... //
return out;
}
Now, everything chains properly. Notice that this function is a free function, not a member function, and that the left-hand side is of type ostream and the right-hand side has the type of your class in it. This is the conventional way to do this, since if you try overloading operator << as a member function, the left-hand side will be an operand of your class type, which is backwards from how stream insertion is supposed to work. If you need to specifically access private fields of your class in the course of implementing this function, make it a friend:
class XY {
public:
...
friend ostream& operator<< (ostream& out, const XY& myXY);
};
ostream& operator<< (ostream& out, const XY &myXY) {
...
return out;
}
Correct way to overload << operator in your case is
ostream& operator<<(ostream& os, const XY& c)
{
os << c.X__ <<" "<< c.Y__ ;
return os;
}
You have overloaded operator<< in a way that's incompatible with the conventions you must follow when you intend to use the operator with a std::ostream object like std::cout.
In fact, your operator<<'s signature has nothing to do with streams at all! It is just a member function of XY which takes another XY (which it then does not use), returns a string and has an unsual name. Here's how you would theoretically call it:
XY a(1,2);
XY b(1,2);
std::string x = (a << b);
The correct way to overload operator<< for use with streams is to make the operator a non-member function, add a stream reference parameter and return a stream reference to the stream argument. You also do not need a string stream; you write directly to the stream you get:
#include <iostream>
class XY
{
int x;
int y;
public:
XY(int x, int y) : x(x), y(y) {}
int X() const { return x; }
int Y() const { return y; }
};
std::ostream& operator<<(std::ostream& os, XY const& c)
{
os << "{ " << c.X() << ", " << c.Y() << " }";
return os;
}
int main()
{
XY a(1,2);
std::cout << a;
}

How to invoke an overloaded parent cout friend class from a derived class?

Imagine a setup as follows. How do I invoke the base class cout from within the derived class cout? I could use the getBrand() method, but I feel like I should be able to directly access the base class' cout friend function.
I hacked a bit, and tried this.Brand and also just Brand. No luck.
class Brand {
public:
Brand(std::string brand):brand_(brand) {};
friend std::ostream & operator << (std::ostream & out, const Brand & b) {
out << b.brand_ << ' ';
return out;
}
std::string getBrand()const { return brand_; }
private:
std::string brand_;
}
class Cheese : public Brand {
public:
Cheese(std::string brand, std::string type):Brand(brand), type_(type) {};
friend std::ostream & operator << (std::ostream & out, const Cheese & c) {
out << /* THIS.BRAND?! BRAND?! getBrand() meh.. */ << ' ' << c.type_ << std::endl; // <-- HERE
return out;
}
private:
std::string type_;
}
int main() {
Cheese c("Cabot Clothbound", "Cheddar");
std::cout << c << std::endl;
}
DESIRED OUTPUT
Cabot Clothbound Cheddar
You could invoke the overloaded operator << of the Base class from the derived class. Since, you declared the operator as a friend, you could simply cast the the derived class to a base class:
class Cheese : public Brand {
public:
Cheese(std::string brand, std::string type):Brand(brand), type_(type) {};
friend std::ostream & operator << (std::ostream & out, const Cheese & c) {
//ADDED
out << static_cast<const Brand&>(c) << c.type_ << std::endl;
return out;
}
private:
std::string type_;
};
Output:
Cabot Clothbound Cheddar
See it Live
Cast it, like this:
friend std::ostream& operator<<(std::ostream& out, const Cheese& c)
{
out << static_cast<const Brand &>(c);
out << c.type_ << std::endl;
return out;
}
All other answers are responding correctly to your specific question, but whenever you'll try to use polymorphism like this:
Brand const &c = Cheese("Cabot Clothbound", "Cheddar");
std::cout << c << std::endl;
operator << corresponding to Brand will be called instead of Cheese's.
The good way to do it is to use a virtual print member function:
class Brand {
public:
Brand(std::string const & brand):brand_(brand) {}
virtual ~Brand() {}
virtual void print(std::ostream & out) const {
out << brand_;
}
std::string const & getBrand()const { return brand_; }
private:
std::string brand_;
};
class Cheese : public Brand {
public:
Cheese(std::string const & brand, std::string const & type):Brand(brand), type_(type) {}
void print(std::ostream & out) const override {
Brand::print(out); // calling base print()
out << ' ' << type_ << std::endl;
}
private:
std::string type_;
};
Then, you only need a single operator << for the base class which will call your print virtual member function:
std::ostream & operator << (std::ostream & out, const Brand & b) {
b.print(out);
return out;
}
DEMO
You obviously can't do anything like Brand::operator<<, because both operator<< are defined as friend and thus they are not member functions.
If you want to invoke operator<<(std::ostream&, const Brand&), you just have to pass correct types to that, and since Derived classes can be easily casted to Base classes, you can just do
friend std::ostream & operator << (std::ostream & out, const Cheese & c) {
out << static_cast<const Brand&>(c) << ' ' << c.type_ << std::endl;
return out;
}

operator << overloading often fails if operator is const?

If I want to overload the << operator to use cout on a class, it should look like this:
template <typename coutT>
friend ostream& operator << (ostream &, const vector3D<coutT>&);
inside the class, and
template <typename coutT>
ostream& operator << (ostream & os,const vector3D<coutT>& v)
{
os << "x: " << v.x<< " y: " << v.y << " z: " << v.z;
return os;
}
on the outside. Please take note of the const at the second operand.
This sample of code works just fine. Now to the problem.
If I were to write the overload function using the getters for the fields, instead of addressing them directly (since operator<< is a friend), my compiler would throw an error:
template <typename coutT>
ostream& operator << (ostream & os,const vector3D<coutT>& v)
{
os << "x: " << v.getX() << " y: " << v.getY() << " z: " << v.getZ();
return os;
}
The error:
(VisualStudio2012) errorC2662: "this-pointer cannot be converted from "const vector3D" in "vector3D&""
An important note is that deleting the "const" at the second operand so that it's like
ostream& operator << (ostream & os,vector3D<coutT>& v){...}
ended compiler errors, but since I don't want to change v, it should really be a const.
I should also mention that I think it may have to do with method calls in general, but I'm not sure.
edit:
So it is solved, declaring functions as const sticks to const-correctness.
The error message explains it in the way that it cannot cast the const type to a non-const one.
btw.: I'm actually impressed about the quick responses.
The getter function should be declared const if you want to use it that way.
For example
int getValue() const {
return x;
}
Complete example:
#include <iostream>
#include <vector>
using namespace std;
class Foo {
int x;
public:
Foo(int a) : x(a) {
}
int getValue() const {
return x;
}
friend ostream & operator<<(ostream & out, const Foo & foo) {
return out << foo.getValue();
}
};
int main() {
vector<Foo> foo_vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (vector<Foo>::iterator it = foo_vec.begin(); it != foo_vec.end(); it++) {
cout << *it << ", ";
}
return 0;
}
Your problem is that you didn't mark the get functions const:
They need to look like this:
double getX() const;
You need to make the accessor functions const:
struct V
{
int getX() const { /* ... */ }
^^^^^
};
Only const member functions can be invoked on constant object values. In turn, const member functions cannot mutate the object. Thus const-correctness guarantees that a constant value cannot be mutated by invoking any of its member functions.

Which operator gets invoked upon object evaluation?

I would like to print the id of my object when the object is being evaluated (third line in my main function "one = two; should output "Object id: 2"). I know that the assignment operator is only invoked for the lvalue, a conversation operator to itself will never be called and I don't want to use the function call operator.
Any ideas how this can be done, which operator must I overload?
P.S.: Please ignore any saneness of the code, I only care about identifying the right to-be-overloaded operator.
#include <iostream>
class Object
{
public:
Object( int id ) : id_( id )
{
}
//Assignment operator only invoked for lvalue
Object& operator= (const Object& other)
{
std::cout << "Object id: " << id_ << std::endl;
return *this;
}
//Conversion operator to itself will never be called
operator Object() const
{
return *(this);
}
//Function call operator - not what I mean
Object operator()()
{
std::cout << "Object id: " << id_ << std::endl;
return *(this);
}
private:
int id_;
};
int main()
{
Object one(1);
Object two(2);
one = two;
one = two();
return 0;
}
The concept of "object evaluation" isn't really present in C++. An expression can be evaluated, of course, and operator overloading fits into this: foo = bar invokes any overloaded operator= which matches the operands (and in the case of operator= specifically, must be a member of the LHS class type). But it's the assignment that's being evaluated, not foo or bar (and note that in the context of the operator overload, these are present as pointers or references, so it's not inevitable that either one will be evaluated at all).
The appropriate solution here will depend on what it is you're trying to accomplish. But there's no one function that automatically fires whenever your code mentions bar.
#include <iostream>
class Object
{
public:
Object( int id ) : id_( id )
{
}
//Assignment operator only invoked for lvalue
Object& operator= (const Object& other)
{
std::cout << "Object id: " << other.id_ << std::endl;
return *this;
}
private:
int id_;
};
int main()
{
Object one(1);
Object two(2);
one = two;
return 0;
}
I tried this to see if Mat was right, turns out it compiles and prints "Object id: 2" as expected.
So, this line:
one = two;
Will call this function that you already have:
Object& operator= (const Object& other)
{
std::cout << "Object id: " << id_ << std::endl;
return *this;
}
However, let's note that there are two Object objects that are visible in that function.
Object& operator= (const Object& other)
{
std::cout << "Object(" << this->id_ << ")";
std::cout << " = ";
std::cout << "Object(" << other.id_ << ")";
std::cout << "\n";
return *this;
}
You can see a full example where we run this code at ideone.com.