【问题标题】:Data loss every time I push an object into a vector每次将对象推入向量时都会丢失数据
【发布时间】:2018-05-20 18:38:32
【问题描述】:

我有一个学校项目,我应该在其中构建一个模板类Vanzare,意思是销售。我有 2 个 STL 向量,一个用于库存汽车,一个用于已售汽车,还有 2 个变量用于计算库存汽车数量和售出汽车数量。

该类应该有 -= 运算符重载,并且应该出售汽车,这意味着将其从库存向量中删除(名为 stoc)并将其添加到已售向量中(名为 vandut) .

我还重载了 += 运算符以将汽车添加到库存中。

我拥有的汽车类型都是从基类Masina派生出来的,其中一些还有额外的字段。

问题在于,每当我将+=-=(或一般push_back())用于具有额外字段(与基类相比)的任何内容时,它都会破坏向量中的先前元素。所以我不能在不丢失信息的情况下存储任何派生对象。

我还被告知,对整个班级进行专业化可能会有所帮助,但没有。

模板类从第 300 行开始(抱歉,我不知道如何突出显示它)。如果我写的不清楚,我很抱歉,我对所有这些面向对象的东西有点陌生。提前谢谢!

编辑:我尽我所能来精简程序,但它仍然有 250 行代码。我还将(希望一切)重命名为英语。当我向向量中添加对象时,sh 字段仍然会丢失。

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

【问题讨论】:

  • 这是很多代码。请隔离问题,创建一个单独的程序并为我们重新创建它。我们在这里更喜欢一个最小的、可验证的例子。
  • 如果要保留多态性并避免对象切片,请保留指针向量。
  • 我认为这也值得一提:您通常应该更喜欢 emplace_back 而不是 push_back。 1.push_back vs emplace_back 2.Tip of the Week #112: emplace vs. push_back
  • 通过做一个最小的例子,我们并不是要让你的程序尽可能短。我们的意思是分别测试每个部件并消除正常工作的部件。您还应该学习使用调试器来单步调试您的代码。

标签: c++ class templates vector stl


【解决方案1】:

您的所有VAN 构造函数都存在逻辑错误:

  1. 在默认构造函数中,sh 成员根本没有被初始化,所以它的值是不确定的。

  2. 在转换构造函数中,如果 s 参数为 0,则不会初始化 sh 成员,因此在这种情况下它的值是不确定的。您的 operator&gt;&gt; 有一个类似的逻辑错误,即如果输入为 0,它不会更新 m.sh 成员。

  3. 在复制构造函数中,sh 成员根本没有从m 复制,所以它的值是不确定的。

当您将VAN 对象推入您的vector 时,会生成该对象的副本。如果向量需要重新分配其数组以增加其容量,则会生成现有元素的新副本。由于您的复制构造函数已损坏,这就是您丢失 sh 值的原因。

您的 VAN 构造函数需要看起来更像这样 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:对于拷贝构造函数,其实可以完全省略,让编译器自动为你生成合适的拷贝构造函数。

而您的 operator&gt;&gt; 需要看起来更像这样:

istream& operator>>(istream& in , VAN& m)
{
    in >> (Car&)m;
    cout << "Second Hand: ";
    int x;
    in >> x;
    m.sh = (x != 0);
    return in;
}

在一些旁注:

  • 您的sh 成员被声明为int,但显然应该改为bool

  • VAN 不需要也不应该被声明为 friendCar。如果VAN 需要直接访问Car 的私​​有成员,则应将它们声明为protected

【讨论】:

    猜你喜欢
    • 2020-12-06
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多