-1

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;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 4
    This is a lot of code to go through. Please isolate the problem, create a separate program and re-create it for us. We prefer a minimal, verifiable example here. – Sailanarmo May 20 '18 at 18:55
  • Keep a vector of pointers if you want to preserve polymorphism and avoid object slicing. – Jesper Juhl May 20 '18 at 19:34
  • I think this is worth mentioning, as well: you should generally prefer emplace_back over push_back. 1. [push_back vs emplace_back](https://stackoverflow.com/questions/4303513/push-back-vs-emplace-back) 2. [Tip of the Week #112: emplace vs. push_back](https://abseil.io/tips/112) – Jose Fernando Lopez Fernandez May 20 '18 at 20:26
  • By making a minimal example, we don't mean trying to make your program as short as possible. We mean testing each part separately and eliminating the parts that are working properly. You should also learn to use a debugger to step through your code. – eesiraed May 21 '18 at 02:21

1 Answers1

0

There are logic errors in ALL of your VAN constructors:

  1. in the default constructor, the sh member is not being initialized at all, so it's value is indeterminate.

  2. 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.

  3. 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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770