doing operator overloading and polymorphism correctly - c++

I have two wrapper classes for string and int and one to represent Binary Operation and overloading the operator << to write them in a string format. Unfortunately, I can't overload << without friend function and I can't get polymorphism without virtual and can't use friend with virtual !!
#include <iostream>
#include <string>
class AST {};
class expr: public AST {};
class operator_: public AST {};
class BinOp: public expr {
private:
expr *_left;
expr *_right;
operator_ *_op;
public:
BinOp(expr *p_left, expr *p_right, operator_ *p_op):_left(p_left),_right(p_right),_op(p_op) {}
friend std::ostream &operator<< (std::ostream &out, const BinOp &binop) {
out << (binop._left) << " " << (binop._op) << " " << (binop._right);
}
};
class LShift: public operator_ {
public:
LShift() {}
friend std::ostream &operator<< (std::ostream &out, const LShift &lshift) {
out << "<<";
}
};
class Name: public expr {
private:
std::string _id;
public:
Name(std::string p_id) { _id = p_id; }
friend std::ostream &operator<< (std::ostream &out, const Name &name) {
out << name._id;
}
};
class Num: public expr {
private:
int n;
public:
Num(int p_n) { n = p_n; }
friend std::ostream &operator<< (std::ostream &out, const Num &num) {
out << num.n;
}
};
int main() {
auto name = Name("x");
auto num = Num(5);
auto lshift = LShift();
auto binop = BinOp(&name, &num, &lshift);
std::cout << binop << '\n';
return 0;
}
So the program mentioned above outputs the pointer,
0x7ffd05935db0 0x7ffd05935d8b 0x7ffd05935d8c
but instead of a pointer, I need the objects needed to print.
x << 5

In general, having operator overloading an polymorphism in the same class is an indication that you're mixing value-style classes and identity-style classes, and thus a C++-specific code smell.
But I would say that the stream insertion operator is an exception.
The solution is to overload the operator once, and forward to a function that is more amenable to overriding.
class AST {
public:
virtual void print(std::ostream& s) const = 0;
virtual ~AST() {} // you probably want this one too
};
// no need for friendliness
std::ostream& operator <<(std::ostream& s, const AST& node) {
node.print(s);
return s;
}
And then you put the actual printing logic into the print overrides of each class.
But I also feel the need to remark that your AST class doesn't seem useful. There is really nothing an operator and a binary expression have in common. It's also conceptually wrong to say that an operator or an expression is an abstract syntax tree. An expression is a part of an AST, a single node in the tree. An operator is a part of an expression. The entire tree is something different.
You should have separate hierarchy roots for operator_ and expr. And yes, that probably means you have to do the printing stuff twice. It's worth it.

Related

Dynamic cast to derived type in operator<<

I have a base class Tag and a child class TagSet, that inherits from Tag.
class Tag
{
public:
Tag(std::string);
std::string tag;
};
std::ostream & operator <<(std::ostream &os, const Tag &t);
class TagSet : public Tag
{
public:
TagSet();
};
std::ostream & operator <<(std::ostream &os, const TagSet &ts);
and their implementations
Tag::Tag(std::string t)
: tag(t)
{}
std::ostream & operator <<( std::ostream &os, const Tag &t )
{
os << "This is a tag";
return os;
}
TagSet::TagSet()
: Tag("SET")
{}
std::ostream & operator <<(std::ostream &os, const TagSet &ts)
{
os << "This is a TagSet";
return os;
}
I want to include a third class TagList that has a member std::vector<Tag*>, which can hold either Tag* instances or TagSet* instances. I want to define the << operator for TagList such that it uses the Tag version of operator<< if the element is a Tag or the TagSet version of operator<< if the element is a TagSet. This is my attempt:
std::ostream & operator <<(std::ostream &os, const TagList &ts)
{
for (auto t : ts.tags)
{
if (t->tag == "SET")
{
TagSet * tset = dynamic_cast<TagSet*>(t);
os << *tset << ", ";
}
else os << t->tag << ", ";
}
}
The code crashes at runtime. I checked the tset pointer and it isn't null. Probably it's a bad cast.
What is the correct way to do this? Is the problem something to do with consts in the operator<< function? Other suggests for how to achieve this are welcome.
The rest of the TagList implementation is here for completeness:
class TagList
{
public:
TagList(std::vector<Tag*> taglist);
std::vector<Tag*> tags;
typedef std::vector<Tag*>::const_iterator const_iterator;
const_iterator begin() const { return tags.begin(); }
const_iterator end() const { return tags.end(); }
};
std::ostream & operator <<(std::ostream &os, const TagList &ts);
and
TagList::TagList(std::vector<Tag*> tagvec)
: tags(tagvec.begin(), tagvec.end())
{}
If I may suggest a different solution to the problem of outputting your Tag objects, then have only a single operator overload, for Tag const&, and then have that call a virtual output function in the Tag structure. Then override that function in the inherited classes.
Perhaps something like
struct Tag
{
...
virtual std::ostream& output(std::ostream& out)
{
return out << "This is Tag\n";
}
friend std::ostream& operator<<(std::ostream& out, Tag const& tag)
{
return tag.output(out);
}
};
struct TagSet : Tag
{
...
std::ostream& output(std::ostream& out) override
{
return out << "This is TagSet\n";
}
};
Then to output the list
for (auto t : ts.tags)
std::cout << *t;
You cannot do that, because operator<< is not virtual.
Define a virtual print method instead, and use that in operator<<, e.g.
class Tag {
public:
virtual void print(std::ostream &f) const;
};
std::ostream & operator <<(std::ostream &os, const Tag &t)
{
t->print(os);
return os;
}
Now you can use method print() in TagList as well without any cast at all:
std::ostream & operator <<(std::ostream &os, const TagList &ts)
{
for (auto t : ts.tags) {
t->print(os);
os << ", ";
}
}
or implicit
for (auto t : ts.tags) {
os << *t << ", ";
}
Your current approach is essentially a hand-written RTTI with extra memory overhead. Mixing it with build-in RTTI by using dynamic cast won't work since classes Tag and TagSet are not polymorphic and build-in RTTI for objects of these types is not available at runtime to perform such cast. If you insist of using hand-written RTTI then you need to perform a static_cast.
TagSet & tset{static_cast<TagSet &>(*t)};

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;
}

C++ - ostream (<<) overloading

I was wondering if there is any way to overload the << operator for a class without declaring it as a friend function. My professor said this is the only way to do it, but I wanted to know if there is another way that he was unaware of.
There is no need to make the operator<< function a friend of the class as long as everything you want to be output is accessible through the public interface of the class.
You need to declare it is as friend function if and only if you need access to it's private members.
You can always do this without using friend function if:
1) No private member access is required.
2) You provide a mechanism to access your private member otherwise. e.g.
class foo
{
int myValue;
public:
int getValue()
{
return myValue;
}
}
Yes, you can
std::ostream& operator<<(std::ostream &stream, WHATEVER_TYPE var) {
std::string str = somehowstringify(var);
return stream << str;
}
Note however that by virtue of it being a non-member non-friend function it can of course only access the public interface of std::ostream, this usually isn't a problem.
Yes, one way to do it is like this:
class Node
{
public:
// other parts of the class here
std::ostream& put(std::ostream& out) const { return out << n; };
private:
int n;
};
std::ostream& operator<<(std::ostream& out, const Node& node) {
return node.put(out);
}
As R Sahu has pointed out, the requirement is that the operator should be able to access everything it has to display.
Here are a few possible options
1.Adding the overloaded function as a friend function
2.Making all the required data members of the class accessible for the function using either public accessor methods or public data members
class MyClass {
private:
int a;
int b;
int c;
public:
MyClass(int x,int y,int z):a(x),b(y),c(z) {};
MyClass():a(0),b(0),c(0) {};
int geta() { return a; }
int getb() { return b; }
int getc() { return c; }
};
std::ostream& operator<<(std::ostream &ostr,MyClass &myclass) {
ostr << myclass.geta()<<" - " << myclass.getb() << " - " << myclass.getc() ;
return ostr;
}
int main (int argc, char const* argv[])
{
MyClass A(4,5,6);
cout << A <<endl;
return 0;
}
3.Add a public helper function , say output with the signature std::ostream& output(std::ostream& str) and use it later in the operator function.

How do I make a class in C++ so that it acts like a native int class

I am learning C++, and learned that int-types are just premade classes. So I thought maybe i should try to create one.
What I want to do basically is a
normal class of int
int x;
x=7;
cout << x;
// Output is 7 on screen.
so similarly...
abc x;
x=7;
cout << x;
What would I put in
class abc{
\\ HERE!!!!!!
};
so I could do this
class SomeClass {
public:
int x;
SomeClass(int x) {
this->x = x;
}
};
int main(int argc, char *argv[]) {
SomeClass s = 5;
cout << s.x << "\n"; // 5
s = 17;
cout << s.x << "\n"; // 17
return 0;
}
But as you can see I have to use s.x to print the value - I just want to use 's'.
I am doing it as an experiment, I don't want to hear about how this method is good or bad, pointless or revolutionary, or can 't be done. I remember once I did it. But only by copying and pasting code that I didn't fully understand, and have even forgotten about.
and learned that int, types, are just premade classes
This is completely false. Still, you have complete control on how your class will behave in expressions, since you can overload (almost) any operator. What you are missing here is the usual operator<< overload that is invoked when you do:
cout<<s;
You can create it like this:
std::ostream & operator<<(std::ostream & os, const SomeClass & Right)
{
Os<<Right.x;
return Os;
}
For more information, see the FAQ about operator overloading.
the << and >> are basically function names. you need to define them for your class. same with the +, -, * and all the other operators. here is how:
http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html
You need to overload operator<< for your class, like so:
class abc
{
public:
abc(int x) : m_X(x) {}
private:
int m_X;
friend std::ostream& operator<<(std::ostream& stream, const abc& obj);
};
std::ostream& operator<<(std::ostream& os, const abc& obj)
{
return os << obj.m_X;
}
You don't have to friend your operator<< overload unless you want to access protected/private members.
You must define in your class abc cast operator to int and assignment operator from int, like in this template class:
template <class T>
class TypeWrapper {
public:
TypeWrapper(const T& value) : value(value) {}
TypeWrapper() {}
operator T() const { return value; }
TypeWrapper& operator (const T& value) { this->value = value; return *this; }
private:
T value;
};
int main() {
TypeWrapper<int> x;
x = 7;
cout << x << endl;
}
You want to overload the output operator:
std::ostream& operator<< (std::ostream& out, SomeClass const& value) {
// format value appropriately
return out;
}

C++ distinguishing structurally identical classes

I have several types that share common behaviour and with same constructors and operators. Some look like this:
class NumberOfFingers
{
public:
void operator=(int t) { this->value = t; }
operator int() const { return this->value; }
private:
int value;
};
NumberOfToes is identical.
Each class has different behaviour, here is an example:
std::ostream& operator<<(std::ostream &s, const NumberOfFingers &fingers)
{
s << fingers << " fingers\n";
}
std::ostream& operator<<(std::ostream &s, const NumberOfFingers &toes)
{
s << toes << " toes\n";
}
How can I minimise the duplication in the class definitions, whilst keeping class types distinct? I don't want to have NumberOfFingers and NumberOfToes derive from a common base class because I lose the constructor and operators. I would guess a good answer would involve templates.
Yes, you are correct in that it would involve templates :)
enum {FINGERS, TOES...};
...
template<unsigned Type> //maybe template<enum Type> but I havent compiled this.
class NumberOfType
{
public:
void operator=(int t) { this->value = t; }
operator int() const { return this->value; }
private:
int value;
};
...
typedef NumberOfType<FINGERS> NumberOfFinger
typedef NumberOfType<TOES> NumberOfToes
... so on and so forth.