Overloading addition operator with many objects c++ - c++

I need to overload the addition operator of multiple different objects and return a 'cluster object:
"Overload the addition operator(+) to add any combination of instances for Desktops, Laptops, and Clusters. This operator should return an object of type cluster"
So if I had desktop1+laptop1+laptop2; I would need it to return a cluster that adds all of the RAM, and other variables of each object. But it will only be adding the variables that all of the objects inherit from the computer class. Here is my code of the rest of the project. Thanks!
#include <iostream>
using namespace std;
class computer
{
public:
double RAM;
double CPUSpeed;
int numberOfCores;
double HDDSize;
virtual void print();
};
class desktop : public computer
{
public:
bool hasMonitor;
double monitorSize;
friend istream& operator>> (istream &in, desktop &myDesktop);
};
class laptop : public computer
{
public:
double screenSize;
};
class cluster : public computer
{
public:
int numOfComp;
};
desktop::desktop()
{
RAM = 0;
CPUSpeed = 0;
numberOfCores = 0;
HDDSize = 0;
hasMonitor = 0;
monitorSize = 0;
}
laptop::laptop()
{
RAM = 0;
CPUSpeed = 0;
numberOfCores = 0;
HDDSize = 0;
screenSize = 0;
}
cluster::cluster()
{
RAM = 0;
CPUSpeed = 0;
numberOfCores = 0;
HDDSize = 0;
numOfComp = 0;
}
istream& operator>> (istream &in, desktop &myDesktop)
{
in >> myDesktop.hasMonitor;
in >> myDesktop.monitorSize;
in >> myDesktop.RAM;
in >> myDesktop.CPUSpeed;
in >> myDesktop.HDDSize;
in >> myDesktop.numberOfCores;
return in;
}
istream& operator>> (istream &in, laptop &mylaptop)
{
in >> mylaptop.RAM;
in >> mylaptop.CPUSpeed;
in >> mylaptop.HDDSize;
in >> mylaptop.numberOfCores;
in >> mylaptop.screenSize;
return in;
}
istream& operator>> (istream &in, cluster &myCluster)
{
in >> myCluster.RAM;
in >> myCluster.CPUSpeed;
in >> myCluster.HDDSize;
in >> myCluster.numberOfCores;
in >> myCluster.numOfComp;
return in;
}
operator+(computer &myComp)
{
return

If you only want to add up the values common to all the classes that they inherit from computer, you can do it like this:
cluster operator+(const computer& comp1, const computer& comp2)
{
cluster ret;
ret.RAM = comp1.RAM+comp2.RAM;
ret.CPUSpeed = comp1.CPUSpeed+comp2.CPUSpeed;
ret.numberOfCores = comp1.numberOfCores+comp2.numberOfCores;
ret.HDDSize = comp1.HDDSize+comp2.HDDSize;
return ret;
}
int main()
{
laptop laptop1;
desktop desktop1;
desktop desktop2;
cluster mycluster = laptop1+desktop1+desktop2;
return 0;
}
The chained + operators are evaluated from the right leftwards. The function returns a cluster object, which can then be used as the right hand operand for the next addition.

Related

NULL data stored by overloaded istream

This is part of my polynomial.cpp to get terms by overloading istream
void Newterm(float coef, int deg) {
if (terms == capacity) {
capacity *= 2;
Term* tmp = new Term[capacity];
copy(termArray, termArray + terms, tmp);
termArray = tmp;
delete[] tmp;
}
termArray[terms].degree = deg;
termArray[terms++].coef = coef;
}
friend istream& operator >> (istream& is, Polynomial& pl) {
cout << "number of terms : ";
int t; is >> t;
cout << endl;
float coeff;
int degree;
for (int i = 0; i < t;i++) {
cout << i + 1 << "'s term: ";
is >> coeff >> degree;
pl.Newterm(coeff, degree);
}
return is;
};
of course, i tried to figure out whaaat made this result..
tried:
removing 'for' loop
this actually worked.. but it only works when terms=1
firstly creating term and input data
Newterm(0,0);
is>>pl.termArray[i].coef>>pl.termArray[i].degree;
it couldn't fix anything...
so i think it has to do with loops..
but whyyyy?
Using std::vector instead of doing your own memory managment
(why reinvent the wheel if there is a tested solution in the standard library)
#include <iostream>
#include <vector>
struct Term final
{
Term() = default;
~Term() = default;
Term(int d, double c) :
degree{ d },
coef{ c }
{
}
int degree{ 0 };
double coef{ 1.0 };
};
class Polynomial final
{
public:
Polynomial() = default;
~Polynomial() = default;
explicit Polynomial(const std::initializer_list<Term> terms) :
m_terms{ terms }
{
}
void add(const Term& term)
{
m_terms.push_back(term);
}
private:
std::vector<Term> m_terms;
};
std::istream& operator>>(std::istream& is, Polynomial& polynomial)
{
std::size_t n{ 0 }; // indices are not ints the can't be < 0
is >> n;
for (std::size_t i = 0; i < n; ++i)
{
Term term{};
is >> term.coef;
is >> term.degree;
polynomial.add(term);
}
return is;
}
int main()
{
// to show you that std::vector can handle all the memory managment for you
// constructor with an initializer list that adds 3 terms
// that's also why the Term has a constructor, it is to make it work with
// initializer list
Polynomial p{ { 1,2.0 }, { 2,4.0 }, { 1,-1.0 } };
}

How to operate overload ">>"?

Product **products;
int numProducts = 0;
void setup()
{
ifstream finput("products.txt");
//get # of products first.
finput >> numProducts;
products = new Product* [numProducts];
//get product codes, names & prices.
for(int i=0; i<numProducts; i++) {
products[i] = new Product;
finput >> products[i]->getCode() >> products[i]->getName() >> products[i]->getPrice();
}
}
I am getting an "invalid operands to binary expression" error for this line:
finput >> products[i]->getCode() >> products[i]->getName() >> products[i]->getPrice();
Do I need to operator overload >> and how would I do it?
Let's take a very simple example, assuming a basic definition for Product as:
class Product
{
int code;
string name;
double price;
public:
Product(int code, const std::string& name, double price)
: code{code}, name{name}, price{price}
{}
int getCode() const { return code; }
const std::string& getName() const { return name; }
double getPrice() const { return price; }
};
You can't read in using operator>> directly into the return values from getCode(), getName() or getPrice(). Those are for accessing those values.
Instead, you need to read in the values and construct products from those values like this:
for(int x = 0; x < numProducts; ++x)
{
int code = 0;
string name;
double price = 0;
finput >> code >> name >> price;
products[i] = new Product{code,name,price};
}
Now, you could refactor this into operator>>:
std::istream& operator>>(std::istream& in, Product& p)
{
int code = 0;
string name;
double price = 0;
in >> code >> name >> price;
p = Product{code,name,price};
return in;
}
There are a bunch of other things to consider about this code:
Use std::vector<Product> instead of your own array
The examples below won't work if name has spaces
There's no error checking and operator>> can fail
In your Class, write down this function
friend ifstream& operator >> (ifstream& in, Product& p1)
{
in >> p1.code >> p1.name /* ..etc */;
return in;
}

Data loss every time I push an object into a vector

I have a school project in which I am supposed to build a template class Vanzare meaning sale. I have 2 STL vectors, one for the cars that are in stock, and one for the cars that are sold, and 2 variables that count how many cars are in stock and how many cars are sold.
The class is supposed to have the -= operator overloaded, and it's supposed to sell a car, meaning deleting it from the stock vector (named stoc) and adding it to the sold vector (named vandut).
I also overloaded the += operator to add a car to stock.
The types of cars I have are all derived from the base class Masina, and some of them have extra fields.
The problem is that whenever I use += or -= ( or push_back() in general) for anything that has extra fields (compared to the base class), it breaks the previous elements from the vector. So I can't store any derived objects without loss of information.
I was also told that making a specialization of the whole class might help, but it didn't.
The template class starts around line 300 (I didn't know how to highlight it sorry). I am sorry if what I wrote wasn't clear, I am kinda new to all of this object oriented stuff. Thank you in advance!
Edit: I tried my best to slim the program down as much as I can, but it still has 250 lines of code. I also renamed (hopefully everything) to English. The field sh still gets lost when I add an object to the vector.
#include <iostream>
#include <string.h>
#include <vector>
#include <ctime>
using namespace std;
class Car
{
int capacity;
float length;
int price;
int year;
public:
int getYear();
void setPrice(int);
int getPrice();
Car();
~Car();
Car(int , float , int , int);
Car(const Car&);
friend istream& operator>>(istream& , Car&);
friend ostream& operator<<(ostream& , Car&);
friend class VAN;
};
int Car::getYear()
{
return year;
}
int Car::getPrice()
{
return price;
}
void Car::setPrice(int p)
{
price = p;
}
ostream& operator<<(ostream& out , Car& m)
{
out<<"capacity: "<<m.capacity<<"\nlength: "<<m.length<<"\nprice: "<<m.price<<"\nYear: "<<m.year;
return out;
}
istream& operator>>(istream& in , Car& m)
{
cout<<"capacity: ";
in>>m.capacity;
cout<<"length: ";
in>>m.length;
cout<<"price: ";
in>>m.price;
cout<<"Year: ";
in>>m.year;
return in;
}
Car::Car()
{
capacity = 0;
length = 0;
year = 0;
price = 0;
}
Car::Car(int lit , float lun , int an , int pre)
{
capacity = lit;
length = lun;
year = an;
price = pre;
}
Car::Car(const Car& m)
{
capacity = m.capacity;
length = m.length;
year = m.year;
price = m.price;
}
Car::~Car()
{
capacity = 0;
year = 0;
length = 0;
price = 0;
}
class VAN:public Car
{
int sh;
public:
void setSH(int);
int isSH();
VAN();
~VAN();
VAN(int , float , int , int , int);
VAN(const VAN&);
friend istream& operator>>(istream& , VAN&);
friend ostream& operator<<(ostream& , VAN&);
};
void VAN::setSH(int s)
{
if(s)
sh = 1;
else
sh = 0;
}
int VAN::isSH()
{
return sh;
}
ostream& operator<<(ostream& out , VAN& m)
{
out<<(Car&)m;
out<<endl<<"Second hand: "<<m.sh;
return out;
}
istream& operator>>(istream& in , VAN& m)
{
in>>(Car&)m;
cout<<"Second Hand: ";
int x;
in>>x;
if(x)
m.sh = 1;
return in;
}
VAN::VAN():Car()
{
;
}
VAN::~VAN()
{
;
}
VAN::VAN(int a , float b , int c, int d , int s):Car(a , b, c , d)
{
if(s)
sh = 1;
}
VAN::VAN(const VAN& m):Car(m)
{
;
}
template <class T>
class Sale
{
vector<T> stock;
vector<T> sold;
int nrSold;
int nrStock;
public:
Sale();
Sale<T>& operator += (T&);
template <class U>
friend ostream& operator<<(ostream& , Sale<U>& );
Sale<T>& operator -= (int);
};
template <class T> Sale<T>& Sale<T>::operator -= (int i)
{
nrStock--;
nrSold++;
sold.push_back(stock[i]);
stock.erase(stock.begin()+i);
time_t now = time(0);
tm *ltm = localtime(&now);
if(ltm->tm_mon == 5 || ltm->tm_mon == 6 || ltm->tm_mon == 7)
{
(sold[nrSold-1]).setPret((sold[nrSold-1].getPret()/10)*9);
}
return *this;
}
template <class T> Sale<T>::Sale()
{
nrSold = 0;
nrStock = 0;
}
template <class T> ostream& operator<<(ostream& out, Sale<T>& v)
{
out<<"\nWhat we have in stock:\n\n";
for(int i = 0; i < v.nrStock ; i++)
{
out<<v.stock[i]<<endl;
}
cout<<"\nWhat we sold:\n\n";
for(int i = 0; i < v.nrSold ; i++)
{
out<<v.sold[i]<<endl;
}
return out;
}
template <class T> Sale<T>& Sale<T>::operator += (T& t)
{
nrStock ++;
stock.push_back(t);
return *this;
}
int main()
{
VAN x;
cin>>x;
cout<<x;
Sale<VAN> v;
v += x;
v += x;
cout<<v;
}
There are logic errors in ALL of your VAN constructors:
in the default constructor, the sh member is not being initialized at all, so it's value is indeterminate.
In the conversion constructor, the sh member is not being initialized if the s parameter is 0, so it's value is indeterminate in that case. Your operator>> has a similar logic error that it is not updating the m.sh member if the input is 0.
in the copy constructor, the sh member is not being copied from m at all, so it's value is indeterminate.
When you push a VAN object into your vector, a copy of the object is made. And if the vector needs to reallocate its array to grow its capacity, new copies of existing elements are made. Since your copy constructor is broken, that is why you are losing your sh values.
Your VAN constructors need to look more like this instead 1:
VAN::VAN() : Car(), sh(0)
{
}
VAN::VAN(int a , float b , int c, int d , int s) : Car(a , b, c , d)
{
sh = (s != 0);
}
VAN::VAN(const VAN& m) : Car(m), sh(m.sh)
{
}
1: in the case of the copy constructor, you can actually omit it completely, and let the compiler auto-generate a suitable copy constructor for you.
And your operator>> needs to look more like this instead:
istream& operator>>(istream& in , VAN& m)
{
in >> (Car&)m;
cout << "Second Hand: ";
int x;
in >> x;
m.sh = (x != 0);
return in;
}
On a couple of side notes:
your sh member is declared as an int, but it clearly should be a bool instead.
VAN does not need to, and should not, be declared as a friend of Car. If VAN needs direct access to Car's private members, they should be declared as protected instead.

usage of istream in class constructor c++

I have a text file that contains a list of students and their marks and looks like this:
Name_of_student 78 4; 98 5; 90 5; 63 3;
...
I have an assignment to create a class that will read and store that data. This is what I've done so far.
group.h
class Subject {
public:
Subject(int mark0, int mark1);
Subject();
int get_m0() { return mark0; }
int get_m1() { return mark1; }
private:
int mark0;
int mark1;
};
class Student {
public:
Student(string name);
Student();
vector<Subject>my_marks;
string get_name() { return name; }
private:
string name;
};
class Reading
{
public:
Reading(vector<Student>, istream& );
istream& read_student();
private:
vector<Student>group;
istream& is;
};
text.cpp
Subject::Subject(int m0, int m1) :
mark0(m0), mark1(m1) {}
Subject::Subject() :
mark0(1), mark1(1) {}
Student::Student(string n0) :
name(n0) {}
Student::Student() :
name("null") {}
Reading::Reading(vector<Student>group0, istream& is0) :
group(group0), is(is0) {}
istream& Reading::read_student()
{
string n;
is >> n;
if (!is) return is;
Student st = Student(n);
for (int i = 0; i < 4; ++i)
{
int m0, m1;
is >> m0 >> m1;
char ch;
is >> ch;
Subject sub = Subject(m0, m1);
st.my_marks.push_back(sub);
}
group.push_back(st);
return is;
}
It compiles, but refuses to read anything.
int main()
{
ifstream ifs("text");
if(!ifs) error("can`t open input file");
vector<Student> group;
Readding r(group, ifs);
r.read_student();
cout << group.size();
}
And what it shows:
0
If anyone has any ideas I'd appreciate it.
In Reading::read_student(), you are filling up the member variable Reading::group. You are not filling up the function variable group in main.
Use:
int main()
{
ifstream ifs("text");
vector<Student> group;
Readding r(group, ifs);
r.read_student();
cout << r.group.size();
// ^^^^^^^^ access the member variable of r.
}
If you want the function variable group to be filled up, Reading needs to store a reference to the input group.
class Reading
{
public:
Reading(vector<Student> & , istream& );
// ^^^^^^ Take a reference as input
istream& read_student();
private:
vector<Student>& group;
// ^^^^^^ store a reference
istream& is;
};
What i have changed:
group.h
class Reading
{
public:
Reading( istream& );
vector<Student>group;
istream& read_student();
private:
istream& is;
};
text.cpp
Reading::Reading(istream& is0) :
is(is0) {}
int main()
{
ifstream ifs("text");
if(!ifs) error("can`t open input file");
Readding r(ifs);
r.read_student();
cout << r.group.size();
}
And now it works all correct!!!

0xC0000005: Access violation reading location 0xccccccd0. C++

I'm having the above issue when I attempt to set a string (stored in a class) equal to another string. I have combed and combed trying to find if I did not initialize any variables, but I can't find such a situation. In debug mod, I get the above error. In release mode it hangs and Win7 looks for a problem, no major abort or retry window. Here's the relevant code, there is another header file with my main program if you feel it should be included, I'll include the line that causes errors. Language is C++ obviously.
//Error occurs in this area:
Car one;
one = two;
one.addExtra ("Windows");
log << "Car one: " << one << endl;
two = Car(one); // call copy constructor.
//I realize when I call the first one = two, there are no extras
//stored int Car one, which is what differs between the two. Remaining
//code. Extras header:
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Extras
{
public:
friend class Car;
friend int main();
friend ostream& operator << (ostream& os, const Extras& in);
friend class CarLot;
Extras(const Extras& other);
Extras& operator=(Extras &rhs);
Extras(string in);
Extras();
~Extras();
void modify_ext(string* in);
//string ex_list;
private:
int place;
string *ex_list;
};
//Extras.cpp:
#include "Extras.h"
Extras::Extras(string in)
{
delete ex_list;
ex_list = new string;
place = 0;
//ex_list = new string[4];
(*ex_list) = in;
place++;
}
Extras::Extras()
{
//ex_list = new string[4];
place = 0;
//for(int i = 0; i < 4; i++)
ex_list = new string;
*ex_list = "0";
}
//Overloaded << operator for Extras class to
//easily output array contents
ostream& operator<< (ostream& os, Extras const &in)
{
os << *(in.ex_list);
return os;
}
Extras& Extras::operator=(Extras &rhs)
{
if(this != &rhs)
{
//string temp;
//temp = rhs.ex_list;
modify_ext(rhs.ex_list);
cout << endl << endl << ex_list << endl << endl;
place = rhs.place;
}
return *this;
}
Extras::Extras(const Extras& other) : place(other.place), ex_list(other.ex_list)
{
//for(int i = 0; i < 4; i++)
//ex_list = other.ex_list;
}
void Extras::modify_ext(string* in)
{
delete ex_list;
ex_list = new string;
(*ex_list).resize((*in).size());
for(unsigned int i = 0; i < (*in).size(); i++)
ex_list[i] = in[i];
}
Extras::~Extras()
{
delete ex_list;
place = 0;
}
//Car Header:
#include "Extras.h"
class Car
{
public:
friend class Extras;
friend Extras& Extras::operator=(Extras &rhs);
friend int main();
friend ostream& operator<< (ostream& os, const Car& in);
friend class CarLot;
friend void add_extra();
~Car();
Car();
Car(Car& other);
Car(string in_name, int in_year, string in_color, float in_cost);
Car& operator=(Car const &rhs);
void edit_extr(int in);
void addExtra(string in);
private:
string name, color;
int year, extr_num;
float cost;
Extras *extr;
};
//Car.cpp:
#include "car.h"
//Constructor
Car::Car(string in_name, int in_year, string in_color, float in_cost)
{
name = in_name;
color = in_color;
year = in_year;
cost = in_cost;
extr = new Extras[3];
extr_num = 0;
}
//Overloaded = operator
Car& Car::operator=(Car const &rhs)
{
if(this != &rhs)
{
name = rhs.name;
color = rhs.color;
year = rhs.year;
cost = rhs.cost;
//delete extr;
extr = rhs.extr;
extr_num = rhs.extr_num;
}
return *this;
}
//Default Constructor
Car::Car()
{
name = "TEMP";
color = "BLUE";
year = 0;
cost = 0;
extr = new Extras[3];
extr_num = 0;
}
//Destructor
Car::~Car()
{
delete extr;
extr = NULL;
}
//Copy constructor
Car::Car(Car& other) : name(other.name), color(other.color), year(other.year),
cost(other.cost), extr_num(other.extr_num)
{
//delete extr;
for(int i = 0; i < extr_num; i++)
{
extr[i].modify_ext(other.extr[i].ex_list);
extr[i].place = other.extr[i].place;
}
}
//Overloaded << operator for Car class
ostream& operator<< (ostream& os, const Car& in)
{
os.precision(2);
os << in.name << ", " << in.year << ", "
<< in.color << ", $"<< in.cost << ", ";
os << "extras include: ";
for(int k = 0; k < in.extr_num; k++)
{
os << in.extr[k] << ", ";
}
os << endl;
return os;
}
void Car::edit_extr(int in)
{
Extras* temp;
temp = new Extras[in];
for(int i = 0; i < in; i++)
temp[i] = extr[i];
extr_num = in;
delete extr;
extr = temp;
}
void Car::addExtra(string in)
{
if(extr_num == 3)
{
//log << "Car has too many extras.";
return;
}
//edit_extr(extr_num + 1);
*(extr[extr_num].ex_list) = in;
extr[extr_num].place++;
extr_num++;
}
As I said, I have one more additional header, another class, and a main program if those need to be included, but I figured this was more than enough code (sorry!) for anyone to look through. Any help would be incredibly appreciated.
What I'm seeing that's broken:
two = Car(one); // call copy constructor.
No, it creates a temporary object with the copy constructor, passes this to operator=() on two, then destroys the temporary.
Extras& operator=(Extras &rhs);
should be:
Extras& operator=(const Extras &rhs);
Extras::Extras(string in)
{
delete ex_list;
ex_list = new string;
place = 0;
//ex_list = new string[4];
(*ex_list) = in;
place++;
}
Better:
Extras::Extras(const string& in): place(1), ex_list(new string(in))
{
}
Extras::Extras(const Extras& other) : place(other.place), ex_list(other.ex_list)
{
//for(int i = 0; i < 4; i++)
//ex_list = other.ex_list;
}
Looking at your default constructor, it's clear that the Extras object owns the string in ex_list. However, this copy constructor claims ownership of the original object's ex_list. It should make its own copy:
Extras::Extras(const Extras& other): place(other.place),
ex_list(new string(other.ex_list))
{
}
void Extras::modify_ext(string* in)
{
delete ex_list;
ex_list = new string;
(*ex_list).resize((*in).size());
for(unsigned int i = 0; i < (*in).size(); i++)
ex_list[i] = in[i];
}
You're copying the string. All you need is:
void Extras::modify_ext(const string* in)
{
*ex_list = *in;
}
Moving on to the Car...
friend class Extras;
friend Extras& Extras::operator=(Extras &rhs);
friend int main();
friend ostream& operator<< (ostream& os, const Car& in);
friend class CarLot;
friend void add_extra();
You should consider refactoring the code to get rid of these.
Car(Car& other);
Car(string in_name, int in_year, string in_color, float in_cost);
Should be:
Car(const Car& other);
Car(const string& in_name, int in_year, const string& in_color, float in_cost);
References are your friends when passing objects to functions.
I'm going to stop here.
In your constructor you are deleting ex_list. It hasn't even been allocated yet, so this is wrong. Remove that and do this instead when allocating your new string:
ex_list = new string(in);
This way you use the string copy constructor. You can get rid of the rest of whatever you were trying to do below in the constructor since this will do it for you.
Edit:
Actually, there are a ton of problems all throughout this code. Is there any reason you want your string to be a pointer internally? You aren't using pointers correctly in a bunch of different places. I only noticed the first one as I scrolled down.
The allocator in debug builds with VC++ uses some magic values to fill allocated areas. In particular, 0xCC is memory that had been allocated but it now freed. So the address 0xCCCCCCD0, looks suspiciously like a small offset (e.g., to a struct or class member) from a pointer in memory that was freed. Given that, Mark Loeser's answer looks promising.