Operator overloading =, *=. How to make this work? - c++

I have problem with those lines in main:
*tab[1]=test1;
*tab[4]=test2;
It just adds colour, and variables (a,b,h) stay the same. I was trying something like this
cuboid operator=(const cuboid & base)
{
return cuboid(base.colour(), base.valueA(), base.valueB(),base.h_)
}
but this doesn't seem to be working either
next one is this:
*tab[4] * =2;
There is overloaded operator for this method and when I run this there occures some error. No match for operator*=. Operand types are figure and int.
The last one is: *tab[2] = "bright" + *tab[2]; I think that I need a new constructor for this, but where do I make one?
Thanks for any answer !!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
using namespace std;
class figure
{
string * colour_;
public:
figure(): colour_(new string("Empty")) {}
figure(const string & colour): colour_(new string(colour)) {}
figure(const figure & base)
{
colour_=new string(*base.colour_);
}
virtual ~figure() {delete colour_;}
string & colour () const {return *colour_;}
virtual double area () =0;
virtual void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
}
friend ostream & operator <<(ostream &os, const figure & base)
{
base.print(os);
return os;
}
figure & operator=(const figure & base)
{
if(this==&base)
return *this;
else
{
colour_=new string(*base.colour_);
return *this;
}
}
};
class circle :public figure
{
int r_;
public:
circle() : r_(0) {}
circle(const string & colour,const int r) : figure(colour), r_(r) {}
double area()
{
return M_PI*r_*r_;
}
const int & radius() const {return r_;}
void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
where << "Radius: " << radius() << " ";
}
circle & operator=(const circle & base)
{
r_=base.r_;
figure::operator=(base);
return *this;
}
};
class rectangle : public figure
{
int a_;
int b_;
public:
static int ObjectCount_;
rectangle() : a_(0), b_(0) {++ObjectCount_;}
rectangle(const string & colour, const int a, const int b) : figure(colour),a_(a), b_(b) {++ObjectCount_;}
~rectangle() {--ObjectCount_;}
double area()
{
return a_*b_;
}
const int & valueA () const {return a_;}
const int & valueB () const {return b_;}
int & changeA() {return a_;}
int & changeB() {return b_;}
void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
where << "Value A: " << valueA() << " ";
where << "Value B: " << valueB() << " ";
}
rectangle & operator=(const rectangle & base)
{
a_=base.a_;
b_=base.b_;
return *this;
}
static int & ObjectCount() {return ObjectCount_; }
};
class cuboid :public rectangle
{
int h_;
public:
cuboid() : h_(0) {}
cuboid(const string & colour, const int a, const int b, const int h) : rectangle(colour,a,b), h_(h) {}
double area()
{
return 2*valueA()*valueB()+2*valueB()*h_+2*valueA()*h_;
}
void print(ostream& where) const
{
where << "Colour: " << colour() << " ";
where << "Value A: " << valueA() << " ";
where << "Value B: " << valueB() << " ";
where << "Height: " << h_ << " ";
}
cuboid & operator=(const cuboid & base)
{
figure::operator=(base);
rectangle::operator=(base);
h_=base.h_;
return *this;
}
cuboid & operator*=(const int number)
{
h_*=number;
changeA()*=number;
changeB()*=number;
return *this;
}
};
int rectangle::ObjectCount_=0;
int main()
{
figure * tab[5];
const circle test1("black",100);
const cuboid test2("grey", 2,2,2);
tab[0]=new circle("red",1);
tab[1]=new circle;
tab[2]=new rectangle("blue",1,1);
tab[3]=new cuboid("green",1,1,1);
tab[4]=new cuboid;
for(unsigned i=0; i<5;++i)
cout << tab[i]->area() << endl;
for(int i=0; i<5; ++i)
cout<<*tab[i]<<tab[i]->area()<<"\n";
cout << "***********************" << endl;
*tab[1]=test1; // it just assigns a colour, rest stays the same
*tab[4]=test2; // same here
/*
*tab[2] = "bright" + *tab[2]; //?????
*/
//*tab[4]*=2; //some error, no idea
for(int i=0; i<5; ++i)
cout<<*tab[i]<<tab[i]->area()<<"\n";
cout << "$ " << rectangle::ObjectCount() << endl;
for(int i=0; i<5; i++)
delete tab[i];
cout << "$ " << rectangle::ObjectCount() << endl;
}

You are defining array figure* tab[5], so then you make an assigments you are casting all pointers to your objects to figure*:
tab[0]=new circle("red",1);
tab[1]=new circle;
tab[2]=new rectangle("blue",1,1);
tab[3]=new cuboid("green",1,1,1);
tab[4]=new cuboid;
Class figure have only this assigment operator:
figure & operator=(const figure & base) {
if(this==&base)
return *this;
else {
colour_=new string(*base.colour_);
return *this;
}
}
So, then you are doing:
*tab[1]=test1;
*tab[4]=test2;
you are calling that assigment operator from class figure.
Same with operator *=. class figure just doesn't
have it. Thats why you are getting error.

Related

is it possible to deduce user data into inheritance using the overload operator?

for example, I have a base class Unit and Unit has heirs, for example Soldier, Vampire. They have their own lives and damage. Is it possible to display data Vampire, Soldier using a separate class for example StateOfUnits where there is an overload of the output operator.
something like :
base class :
class Unit {
private:
int hpLimit;
int dmg;
int hp;
std::string name;
public:
Unit(int hpLimit = 100, int dmg = 10, const std::string& name = "noname");
~Unit();
int getDamage() const;
int getHP() const;
int getHpLimit() const;
const std::string& getName() const;
};
class that displays statistics:
class StateOfUnits {
///may be some code...
};
std::ostream& operator<<(std::ostream& out, const Unit& unit) {
out << "HP of " << unit.getName() << " is : " << unit.getHP() << "/" << unit.getHpLimit() << std::endl;
out << "Damage of " << unit.getName() << " is : " << unit.getDamage() << std::endl;
return out;
}
main:
int main() {
hp dmg name
Vampire vampire(100,25,"Vampire");
Soldier soldier(120, 20, "Soldier");
cout << soldier << endl;
cout << vampire << endl;
return 0;
}
I hope I explained it clearly.
Yes, if StateOfUnit is a base class:
#include <iostream>
using namespace std;
struct StateOfUnit
{
int hp;
int dmg;
string name;
StateOfUnit(int hp, int dmg, string name)
: hp(hp), dmg(dmg), name(name)
{}
friend ostream& operator<<(ostream& os, const StateOfUnit& s)
{
return os << s.hp << '\t' << s.dmg << '\t' << s.name;
}
};
struct Soldier : StateOfUnit
{
using StateOfUnit::StateOfUnit;
};
struct Vampire : StateOfUnit
{
using StateOfUnit::StateOfUnit;
};
int main() {
Vampire vampire(100,25,"Vampire");
Soldier soldier(120, 20, "Soldier");
cout << soldier << endl;
cout << vampire << endl;
return 0;
}

Accessing data from a nested class elegantly

I have the following class:
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char *StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
struct
{
string HEX() { return Number + " - HEX"; }
string DEC() { return Number + " - DEC"; }
string BIN() { return Number + " - BIN"; }
}ToString;
private:
string Number;
};
And in the end I wand to elegantly access functions from that structure in the following way:
BigNum a = "1234";
cout << "a = " << a.ToString.DEC() << endl;
cout << "b = " << a.ToString.HEX() << endl;
The problem here is that I cannot access variable Number from my structure.
I know that something like this would solve my problem:
struct
{
string HEX(BigNum &parent) { return parent.Number + " - HEX"; }
...
}ToString;
The problem with this solution is that it is not comfortable to always pass a pointer to my instance.
What would be a solution in this case to have data in nested class and in the same time to keep calls as simple as a.ToString.DEC()?
In some way you have to give ToString a reference or a pointer to the BigNum object so you can access Number. How about something like this:
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char* StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
// you can make the struct private so the type is not visible externally
struct ToStringType
{
private:
const BigNum& ref;
public:
ToStringType(const BigNum& r) : ref(r) {}
string HEX() { return ref.Number + " - HEX"; }
string DEC() { return ref.Number + " - DEC"; }
string BIN() { return ref.Number + " - BIN"; }
};
ToStringType ToString{ *this };
private:
string Number;
};
Irrelevant, but I would recommend to simply have separate ToStringHex, ToStringDec and ToStringBin functions. Saves on not storing a reference, plus the API is easier this way.
I don't see any rationale in the ToString struct.
Just leave the methods in BIGNUM and you are done.
However, for this specific application (changing the rendering style of your given objet in an ostream) I would let your object to be printed with the typical operator<< overaloading, and then modify the rendering style using io-manipulators, so that you will be able to:
cout << "a (DEC) = " << BigNum::DEC << a << endl;
cout << "a (HEX) = " << BigNum::HEX << a << endl;
A full fledged example:
#include <iostream>
#include <iomanip>
using namespace std;
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char *StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
static std::ios_base& DEC(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 0;
return os;
}
static std::ios_base& HEX(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 1;
return os;
}
static std::ios_base& BIN(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 2;
return os;
}
private:
static int rendering_style_xalloc;
string Number;
friend ostream &operator << (ostream &ostr, const BigNum &bignum);
};
int BigNum::rendering_style_xalloc = std::ios_base::xalloc();
ostream &operator << (ostream &os, const BigNum &bignum) {
switch (os.iword(BigNum::rendering_style_xalloc)) {
case 0:
os << bignum.Number << " - DEC";
break;
case 1:
os << bignum.Number << " - HEX";
break;
case 2:
os << bignum.Number << " - BIN";
break;
default:
os << bignum.Number << " - UNK";
break;
}
return os;
}
int main(int argc, char **argv)
{
BigNum a = "1234";
cout << BigNum::DEC << "a (DEC) = " << a << endl;
cout << BigNum::HEX << "a (HEX) = " << a << endl;
}
References:
https://en.cppreference.com/w/cpp/io/ios_base/iword

How to overload + operator in a heap allocated var

class a{
int *var = new int;
public:
//constructor and destructor
a(int a):var(new int(5)){}
~a() {delete var;}
int get() const {return *var}
//overload of + oporator
a operator+(const a & rhs){return a(*var+rhs.get()
//overload of ++ operator
a a::operator++ (int)
}
a a::operator+ (const a & rhs) {
return a(*itsRadius + rhs.get());
}
a a::operator++ (int){
a temp(*this);
*itsRadius= *itsRadius+1;
return temp;}
}
now when i do like this:
a c(10),d,g;
g=c+d;
i get g = to some address instead of 15 .
why is that?
and when i fo c++ i get an error (in the distructor when he try to delete),why is that?
Here is a working example. You need also to read about the rule of three:
#include <iostream>
class Int
{
int *_value;
public:
Int(int value) : _value(new int(value))
{
}
~Int()
{
delete _value;
}
Int(Int const &rhs) : _value(new int(*rhs._value))
{
}
Int & operator=(Int const &rhs)
{
*_value = *rhs._value;
return *this;
}
Int operator+(Int &rhs) const
{
return Int(*rhs._value + *_value);
}
operator int() const
{
return *_value;
}
};
int main(void)
{
Int a(10),
b(32),
c(a + b);
std::cout << c << "\n";
a = c;
std::cout << a << "\n";
}
And also, it is a bad idea to use raw C pointers in C++. Read about the std::unique_ptr.
o.k. so i solve the problem , this is the working code :
class SimpleCircle {
int *itsRadius;
public:
SimpleCircle():itsRadius(new int(5)) { cout << "constructor initialized" << endl;}
SimpleCircle(int num) { itsRadius = new int(num); cout << "constructor" << endl;}
SimpleCircle(const SimpleCircle &rhs) : itsRadius(new int(*rhs.itsRadius)){ cout << "copy constructor" << endl; }
~SimpleCircle(){ delete itsRadius; cout << "destructor" << endl;}
//perfect
int get() const {return *itsRadius;}
void set(int num) { *itsRadius = num;}
//-------
//plus operator
SimpleCircle operator+(const SimpleCircle &);
//inc operator
SimpleCircle operator++();
SimpleCircle operator++(int);
//= operator
SimpleCircle & operator=(const SimpleCircle &);
};
SimpleCircle SimpleCircle::operator+ (const SimpleCircle & rhs) {
return SimpleCircle(*itsRadius + *rhs.itsRadius);
}
SimpleCircle SimpleCircle::operator++() {
int a = *itsRadius;
++a;
*itsRadius=a;
return *this;
}
SimpleCircle SimpleCircle::operator++ (int){
SimpleCircle temp(*this);
*itsRadius= *itsRadius+1;
return temp;
}
SimpleCircle & SimpleCircle::operator= (const SimpleCircle & rhs) {
if (this == &rhs)
return *this;
*itsRadius = *rhs.itsRadius;
return *this;
}
int main()
{
SimpleCircle a;
cout << a.get() << endl;
SimpleCircle b(15);
cout << b.get() << endl;
SimpleCircle c = a + b;
cout << "a: "<< a.get() << endl;
cout << "b: " << b.get() << endl;
cout << "c: " << c.get() << endl;
a++;
cout << "a: " << a.get() << endl;
++a;
cout << "a: " << a.get() << endl;
now the reason in the former code i had 2 problem (that was 1 becoase of the outher)
1 c was equal to some garbege instead of a number
2 the program break in the end destructor
the reason was i forgat o add a operator= , so it didn't know how to treat to :
c=a+b;
after i fixed it , all come together nicely

Upcasting and Stream Operator Overloading

As you can see, only the overloaded version of the stream insertion operator for the base class is called on both instances. I understand why it's so. It's because there is no dynamic binding. But, how do I fix it?
#include <iostream>
using namespace std;
class A {
int i;
char c;
public:
A(int i = 0, char c = ' ') {
this->i = i;
this->c = c;
}
int getI() { return i; }
char getC() { return c; }
friend ostream& operator << (ostream&, A&);
};
class B : public A {
double d;
public:
B(int i = 0, char c = ' ', double d = 0.0) : A(i, c), d(d) {}
friend ostream& operator << (ostream&, B&);
};
ostream& operator << (ostream& out, A& a) {
out << "\nInteger: " << a.i << "\nCharacter: " << a.c << endl;
return out;
}
ostream& operator << (ostream& out, B& b) {
out << "\nInteger: " << b.getI() << "\nCharacter: " << b.getC() << "\nDouble: " << b.d << endl;
return out;
}
int main() {
A* a = new A (10, 'x');
B* b = new B(20, 'y', 5.23);
A* array[] = { a, b };
cout << *(array[0]);
cout << "\n______________________________\n";
cout << *(array[1]);
delete a;
delete b;
cin.get();
return 0;
}
How can I make cout << *(array[1]); call the overloaded stream insertion operator that takes an object of B as one of it's arguments?
You can't make it call the overloaded operator, since overloading is resolved at compile time.
To do resolution at runtime, i.e. use dynamic dispatch, you need to move the code that does the printing to a virtual member function.
Then call that from the operator (you only need one, for the base class).
class A
{
public:
// ...
// Override this in B
virtual void print(std::ostream& o) const
{
o << "\nInteger: " << i << "\nCharacter: " << c << endl;
}
// ...
};
ostream& operator << (std::ostream& out, const A& a) {
a.print(out);
return out;
}

Virtual function never gets called

I am trying to implement comparison between different subclasses of the same base class. The comparison should return false if the two instances are of different subclass or return the actual comparison result if they are of the same subclass.
Check the last line in function main: although I have declared equalTo as virtual, only the equalTo method of the base class is called. What is my mistake?
Thanks in advance.
#include <iostream>
#include <fstream>
#include <cmath>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <algorithm>
using namespace std;
bool fileInput = false, fileOutput = false;
class Point
{
public:
double x,y;
Point(){};
Point(double x1, double y1) {
x=x1;
y=y1;
}
bool operator==(Point other) const
{
return (abs(x - other.x) < numeric_limits<double>::epsilon()) and (abs(y - other.y) < numeric_limits<double>::epsilon());
}
};
class Shape
{
protected:
virtual double area() const
{
return 0;
}
virtual void print(std::ostream& os) const {}
virtual void read(std::istream& is) {}
public:
bool compare(Shape* other) {
return area() < other->area();
}
virtual bool equalTo(Shape other) const {
cout << "original";
return false;
}
friend std::ostream& operator<<(std::ostream &strm, const Shape &t)
{
t.print(strm);
return strm;
}
friend std::istream& operator>>(std::istream &strm, Shape &t)
{
t.read(strm);
return strm;
}
};
class Circle : public Shape
{
Point c;
double r;
double area() const
{
return M_PI * r * r;
}
void print(std::ostream &strm) const
{
strm << "Circle. Center coordinates: (" << c.x << "," << c.y << "). Radius: " << r << ". Area: " << area();
}
void read(std::istream &strm)
{
if (!fileInput) cout << "Enter Circle\nCenter: ";
strm >> c.x >> c.y;
if (!fileInput) cout << "Radius: ";
strm >> r;
if (r<0)
throw std::invalid_argument( "The radius cannot be negative." );
}
public:
Circle() {}
Circle(Point x, double y)
{
c = x;
r = y;
}
bool equalTo(Shape other1) const
{
Circle* other = dynamic_cast<Circle*>(&other1);
if (other == 0) return false;
return (c == other->c) and (abs(r - other->r)<numeric_limits<double>::epsilon());
}
};
class Hexagon : public Shape
{
Point c;
double r;
double area() const
{
return 1.5 * sqrt(3) * r * r;
}
void print(std::ostream &strm) const
{
strm << "Hexagon. Center coordinates: (" << c.x << "," << c.y << "). Circumcircle radius: " << r << ". Area: " << area();
}
void read(std::istream &strm)
{
if (!fileInput) cout << "Enter Hexagon\nCenter: ";
strm >> c.x >> c.y;
if (!fileInput) cout << "Circumcircle radius: ";
strm >> r;
if (r<0)
throw std::invalid_argument( "The circumcircle radius cannot be negative." );
}
public:
Hexagon() {}
Hexagon(Point x, double y)
{
c = x;
r = y;
}
bool equalTo(Shape other1) const
{
Hexagon* other = dynamic_cast<Hexagon*>(&other1);
if (other == 0) return false;
return (c == other->c) and (abs(r - other->r)<numeric_limits<double>::epsilon());
}
};
int main()
{
Shape c1 = Circle(Point(0,0), 3);
Shape c2 = Circle(Point(0,0), 3);
Shape c3 = Hexagon(Point(0,0), 3);
cout << "circles: " << c1.equalTo(c2) << endl << "diff: " << c1.equalTo(c3) << endl;
}
This is slicing, when you assign objects to object of type Shape - object was sliced to Shape. Use pointers, or may be references.
Circle p1(Point(0, 0), 3);
Circle p2(Point(0, 0), 3);
Hexagon h1(Point(0, 0), 3);
Shape& c1 = p1;
Shape& c2 = p2;
Shape& c3 = h1;
When you copy-construct a Shape out of a derived class, the object will be sliced so that only the Shape part of it is preserved. Then when you call equalTo, the function is statically bound.
In order to call the derived versions, make c1 and friends into Shape&.