我已经阅读了不同的资源,但感觉我错过了一些东西。当变量(numItems(达到零时,我显式调用析构函数。我有一个打印所有类对象(学生(的循环,但是虽然任何调用析构函数的对象都有一个空白的名字和姓氏,但 ID 和 numItems 变量仍然存在。我是否误解了析构函数的工作原理?为什么它会删除部分而不是全部成员属性?
此外,"项目"存储在动态数组中。只要数组是公共的,我就可以设置和访问它们。但即使使用 setter,如果我尝试填充私有数组,程序也会崩溃。
页眉:
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define ARRAY_MAX 15
using namespace std;
class Student
{
private:
string firstName, lastName;
unsigned int ID, numItems = 0;
typedef string* StringPtr;
//StringPtr items;
public:
int capacity = 15;
string *items = new string[capacity];
Student();
Student(const unsigned int id, const string fName, const string lName);
string getfName() const;
string getlName() const;
unsigned int getnumItems() const;
string getItem(int num);
unsigned int getID() const;
void setfName(string fname);
void setlName(string lname);
void setID(unsigned int id);
void setItem(string str, int num);
int CheckoutCount();
bool CheckOut(const string& item);
bool CheckIn(const string& item);
bool HasCheckedOut(const string& item);
void Clear();
~Student();
//const Student operator+(string rhs);
//void operator+=(string rhs);
//bool operator==(Student rhs);
friend istream& operator>>(istream& input, Student& stu);
friend ostream& operator<<(ostream& output, const Student& stu);
};
#endif // STUDENT_H
定义:
#include "student.h"
using namespace std;
Student::Student()
{
}
Student::Student(const unsigned int id, const string fName, const string lName)
{
firstName = fName;
lastName = lName;
ID = id;
}
string Student::getfName() const
{
return firstName;
}
string Student::getlName() const
{
return lastName;
}
unsigned int Student::getnumItems() const
{
return numItems;
}
string Student::getItem(int num)
{
return items[num];
}
unsigned int Student::getID() const
{
return ID;
}
void Student::setfName(string fname)
{
firstName = fname;
}
void Student::setlName(string lname)
{
lastName = lname;
}
void Student::setID(unsigned int id)
{
if ((id >= 1000) && (id <= 100000))
{
ID = id;
}
else
{
cout << "Attempted ID for " << firstName << " " << lastName << " is invalid. Must be between 1000 and 100,000." << endl;
}
}
void Student::setItem(string str, int num)
{
items[num] = str;
}
int Student::CheckoutCount()
{
return numItems;
}
bool Student::CheckOut(const string & item)
{
if (this->HasCheckedOut(item) == true)
{
return false; // already found item in list, CheckOut failed...
}
else
{
items[numItems] = item;
numItems++;
return true; // CheckOut successful
}
}
bool Student::CheckIn(const string & item)
{
for (int i = 0; i < numItems; i++)
{
if (items[i] == item)
{
for (; i < numItems - 1; i++)
{
// Assign the next element to current location.
items[i] = items[i + 1];
}
// Remove the last element as it has been moved to previous index.
items[numItems - 1] = "";
numItems = numItems - 1;
if (numItems == 0)
{
this->~Student();
}
return true;
}
}
return false;
}
bool Student::HasCheckedOut(const string & item)
{
string *end = items + numItems;
string *result = find(items, end, item);
if (result != end)
{
return true; // found value at "result" pointer location...
}
else
return false;
}
void Student::Clear()
{
ID = 0;
firstName = "";
lastName = "";
delete[] items;
}
Student::~Student()
{
}
istream & operator>>(istream & input, Student & stu)
{
string temp;
input >> stu.ID >> stu.firstName >> stu.lastName >> stu.numItems;
int loopnum = stu.numItems;
if (loopnum > 0)
{
for (int i = 0; i < loopnum; i++)
{
input >> temp;
stu.setItem(temp, i);
}
}
return input;
}
ostream & operator<<(ostream & output, const Student & stu)
{
string s = stu.firstName + " " + stu.lastName;
output << setw(8) << stu.ID << setw(16) << s << setw(8) << stu.numItems;
int loopnum = stu.numItems;
if (loopnum > 0)
{
for (int i = 0; i < loopnum; i++)
{
output << stu.items[i] << " ";
}
}
output << endl << endl;
return output;
}
主要:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include "student.h"
using namespace std;
void fcheck(ifstream &mystream);
int main()
{
ifstream sin("students.txt"); // File input/output variables
ifstream fin("checkins.txt");
ifstream chin("checkouts.txt");
ofstream sout("UpdatedStudentsC.txt");
Student stu1, stu2;
fcheck(sin);
fcheck(fin);
fcheck(chin);
typedef Student* StuPtr;
StuPtr studentList;
int stud_capacity = 50;
studentList = new Student[stud_capacity];
int num_studs = 0;
sout << std::setiosflags(std::ios::left); // justify output to format properly.
while (sin.good()) // While there's data in the file, do stuff.
{
sin >> stu1;
stu1.CheckIn("Towel");
stu1.CheckIn("Locker");
if (stu1.getnumItems() == 0)
{
stu1.~Student();
}
studentList[num_studs] = stu1;
num_studs++;
sout << stu1;
}
for (int i = 0; i < 16; i++)
{
cout << studentList[i].getID() << " " << studentList[i].getfName() << " " << studentList[i].getnumItems() << endl;
}
system("pause");
// Close files
fin.close();
chin.close();
sout.close();
sin.close();
// Quit without error
return 0;
}
void fcheck(ifstream &mystream)
{
if (!mystream) // If we can't find the input file, quit with error message.
{
cout << "file not opened!" << endl;
system("pause");
exit(1);
}
}
如果你不告诉析构函数,它不会删除任何内容(就像现在一样,你的析构函数是空的(。析构函数用于在解除分配对象之前执行一些清理,但它不会解除分配。
隐式调用析构函数
- 当堆栈对象超出范围时,
- 当堆对象使用
delete
解除分配时。
虽然调用析构函数的任何对象的名字和姓氏都是空白的,但 ID 和 numItems 变量仍然存在。
已销毁对象的所有成员变量都不再存在。
无法C++检查物体是否已被销毁。当您尝试访问已销毁对象的成员时,程序将具有未定义的行为。一种可能的行为可能是您可能期望从被破坏的对象中获得的东西,而另一种可能的行为可能是您没有预料到的行为。
你调用局部自动变量的析构函数stu1
,但你没有就地构造一个新对象。当变量超出范围时,它被"再次"销毁。这也会导致程序具有未定义的行为。需要显式调用析构函数是非常罕见的情况,但事实并非如此。