C++ 类析构函数删除部分但不是全部成员数据



我已经阅读了不同的资源,但感觉我错过了一些东西。当变量(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,但你没有就地构造一个新对象。当变量超出范围时,它被"再次"销毁。这也会导致程序具有未定义的行为。需要显式调用析构函数是非常罕见的情况,但事实并非如此。

相关内容

  • 没有找到相关文章

最新更新