C++ - Object slicing even after using pointers - c++

I have a base class Shape, and a derived class Circle which inherits Shape publically:
class Circle : public Shape
I made a C++ vector of Shape pointers, and I assigned Circle pointers to them. I'd read up a lot on object slicing so expected the code to treat the Circle in the vector as a Circle, not a Shape.
Can anyone point out what's wrong with this, given the output?
int main(void) {
vector<Shape*> shapes;
Circle* ncl = new Circle(-8, -8, 0.2f);
shapes.push_back(ncl);
cout << "Expected: " << *ncl << endl;
cout << "Reality: " << *shapes[0] << endl;
}
outputs:
Expected: Circle is at: -8,-8 and has a radius of: 0.2
Reality: Shape centered at point: -8,-8
I have overridden the << operator for both classes out of scope, so I think that's not the problem, but still - here's the code context of my overrides:
inline std::ostream& operator<< (std::ostream& stream, const Shape& shape) {
std::cout << "Shape centered at point: " << shape.getX() << "," << shape.getY();
return stream;
}
inline std::ostream& operator<< (std::ostream& stream, const Circle& circle) {
std::cout << "Circle is at: " << circle.getX() << "," << circle.getY() <<
" and has a radius of: " << circle.getR();
return stream;
}
All in all - I want to be able to access my Circle variables properly while they're stored in the Shape vector (with pointers or otherwise).

There's no slicing involved, it just looks like it.
Overloads are selected at compile time, from the static type as it is known to the compiler.
Since shapes is a vector<Shape*>, *shapes[0] is a Shape&, and that overload is chosen.
The common solution is to only write an operator<< for the base class, and that in turn calls a virtual function on the object.
This will let the dynamic function dispatch select the function at runtime.
For instance:
struct Shape { virtual ostream& print(ostream& os) const { ... } };
struct Circle { ostream& print(ostream& os) const override { ... } };
ostream& operator<<(ostream& os, const Shape& s) { return s.print(os); }

overload resolution is done with static type.
You may use:
std::ostream& operator<< (std::ostream& stream, const Shape& shape) {
shape.print(stream);
return stream;
}
with virtual void Shape::print(std::ostream&) const; to solve your issue.

Related

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 get THIS when overloading operator in C++

I'm a student learning c++. today, I was making a operator overload function to use it in 'cout'. following is a class that contains name, coordinates, etc.
class Custom {
public:
string name;
int x;
int y;
Custom(string _name, int x, int y):name(_name){
this->x = x;
this->y = y;
}
int getDis() const {
return static_cast<int>(sqrt(x*x+y*y));
}
friend ostream& operator << (ostream& os, const Custom& other);
};
ostream& operator << (ostream& os, const Custom& other){
cout << this->name << " : " << getDis() << endl;; // error
return os;
}
However, this code isn't working because of 'THIS' keyword that I was expecting it points to the object. I want to show the object's name and distance value. How can I solve it? I think it is similar with Java's toString method so that it will be able to get THIS.
Thanks in advance for your answer and sorry for poor english. If you don't understand my question don't hesitate to make a comment.
this is available only in member functions, but your operator<< is not a class member (declaring it as friend does not make it a member). It is a global function, as it should be. In a global function, just use the arguments you are passing in:
ostream& operator << (ostream& os, const Custom& other)
{
os << other.name << " : " << other.getDis() << endl;
return os;
}
Also note os replaced cout in the code above. Using cout was an error - the output operator should output to the provided stream, not to cout always.

Given a base class as a parameter, how do I use op<< overload to print the characteristics of a derived class if one is passed?

This is for a homework assignment.
I have a base class Item and a derived class Book.
I have op<< overloaded in Item class:
ostream& operator<<(ostream& out, const Item* const item)
{
out << item->getName() << endl;
return out;
}
As well as in Book class:
ostream& operator<<(ostream& out, const Book* const b)
{
out << b->getPages() << endl;
return out;
}
However only the Item operator is used when I run my code, and it does not print the pages for a book. I have made sure that a "book" gets printed, not just the base class. From the material I've read it seems that overloading the operators for both the base and derived classes is what you're supposed to do, so I'm not sure why my book info doesn't get printed.
You can use polymorphism instead of overloading: add a virtual print method to the classes:
class Item
{
public:
virtual void print(std::ostream& o) const
{
out << getName() << endl;
}
....
};
class Book : public Item
{
public:
virtual void print(std::ostream& o) const
{
out << getPages() << endl;
}
....
};
then use a single ostream& operator<<:
ostream& operator<<(ostream& out, const Item& item)
{
item.print(out);
return out;
}
then
Item* i1 = new Item(....);
Item* i2 = new Book(....);
std::cout << *i1 << " " << *i2 << std::endl;
delete i1;
delete i2;
If you change the derived class function's signature, it's no longer an override of the base class member function.
"However only the Item operator is used when I run my code" - this behaviour might be because you apply it to the pointer*/reference& on the base class;
If you have a container in which you want to store instances of different classes what are derived from the same base class and apply to all of them operator<<, which behaviour will depend on the class of instance for each it is invoked, you have to make sure that:
1.There is at least one virtual method in you base class (this will cause compiler to generate
virtual table for that class and later this table can be used by operator dynamic_cast)
2. Enable RTTI (run-time type identification) in your project : project/c++/language enable RTTI support
3. implement operator<< using the following idea:
ostream& operator<<(ostream& out, const Item& item)
{
if (Book* pBook = dynamic_cast<Book*>(&item)
{
out << pBook ->getName() << endl;
}
if (OtherDerivedClassName* pOtherDerivedClass = dynamic_cast<OtherDerivedClassName*>(&item)
{
// do other interesting things
}
return out;
}

<< operator overloading as a class method in c++

I want to overload the << operator for my class Complex.
The prototype is the following:
void Complex::operator << (ostream &out)
{
out << "The number is: (" << re <<", " << im <<")."<<endl;
}
It works, but I have to call it like this: object << cout for the standart output.
What can I do to make it work backwards, like cout << object?
I know that the 'this' pointer is by default the first parameter sent to the method so that's why the binary operator can work only obj << ostream. I overloaded it as a global function and there were no problems.
Is there a way to overload the << operator as a method and to call it ostream << obj?
I would just use the usual C++ pattern of free function. You can make it friend to your Complex class if you want to make Complex class's private data members visible to it, but usually a complex number class would expose public getters for real part and imaginary coefficient.
class Complex
{
....
friend std::ostream& operator<<(std::ostream &out, const Complex& c);
private:
double re;
double im;
};
inline std::ostream& operator<<(std::ostream &out, const Complex& c)
{
out << "The number is: (" << c.re << ", " << c.im << ").\n";
return out;
}
You could write a free stand operator<< function, try:
std::ostream& operator<< (std::ostream &out, const Complex& cm)
{
out << "The number is: (" << cm.re <<", " << cm.im <<")." << std::endl;
return out;
}
You can define a global function:
void operator << (ostream& out, const Complex& complex)
{
complex.operator<<(out);
}

C++: friend function, derived class

I've got 2 classes, base class is "Port" and derived class is "VintagePort".
As far as I know If i use reference or pointer of base class to object of derived class, it automatically finds correct method, not for reference or pointer but exactly to object(if methods are virtual).
In my situation you can see both classes have friend function "operator<<". But it looks like when I'm using pointer for base class, it calls function only from base class. If I use "cout << VintagePort" It works ok.
My question: Is it working correctly or I should fix something in code?
std::ostream& operator<<(std::ostream& os, const Port& p)
{
os << p.brand << ", " << p.style << ", " << p.bottles << endl;
return os;
}
std::ostream& operator<<(std::ostream& os, const VintagePort& vp)
{
os << (const Port &) vp;
cout << ", " << vp.nickname << ", " << vp.year << endl;
return os;
}
VintagePort vp1;
VintagePort vp2("Gallo", "lekko brazowy", 50, "Blaze", 1990);
VintagePort vp3(vp2);
Port* arr[3];
arr[0] = &vp1;
arr[1] = &vp2;
arr[2] = &vp3;
for (int i = 0; i < 3; i++)
{
cout << ">>>>> " << i+1 << " <<<<<" << endl;
cout << *arr[i]; // call for base class instead derived class
arr[i]->Show();
}
The compiler doesn't now the pointer actually points to an inherited class. One way to solve this is to have a virtual function in the base class for output, and override it in the class inheriting the base class. Then call this virtual method in the output operator.
In C++ polymorphism can only be achieved by means of virtual functions, and operator<< is not one (and cannot be for your purposes, since the first argument is the std::ostream. If you need this sort of behavior, the simple approach is providing a virtual print function in your hierarchy, and have operator<< forward the call performing dynamic dispatch:
struct base { // Don't forget virtual destructors
virtual void print( std::ostream& ) const;
};
struct derived : base {
virtual void print( std::ostream& ) const;
};
std::ostream& operator<<( std::ostream& o, const base& b ) {
b.print( o );
return o;
}