将一个对象写入一个对象,该对象带有指向另一个对象的指针,指向 ASCII 文件 (C++)

Writing an object with a pointer to another object to an ASCII file (C++)

本文关键字:一个对象 指向 ASCII 指针 C++ 文件 对象      更新时间:2023-10-16

我正在制作一个跟踪不同员工的程序。某些员工有合作伙伴(妻子和丈夫),因此所有 Employee 对象都有一个名为"合作伙伴* 合作伙伴"的数据成员(指向合作伙伴对象的指针)。

当我想将员工写入文件时,我的问题就来了。我可以成功地将所有员工数据(姓名、地址、出生日期等)写入文件,但我不知道如何将合作伙伴写入文件。我在合作伙伴类中有一个名为"writeToFile"的函数,它输出所有合作伙伴数据,但我不知道如何将其"连接"到正确的 Employee 对象。我试图只将"partner"对象输出到文件的末尾,但这只是添加了一堆零。

我应该使用两个单独的文件(一个用于员工,一个用于合作伙伴),还是只将合作伙伴数据追加到员工数据?在读回文件时,这不会弄乱文件结构吗,因为只有一些员工有合作伙伴,而一些合作伙伴对象只指向 NULL?

我的类相互继承,因此 Partner 和 Employee 类都继承 Adult 类,后者再次继承 Person 类。

谁能给我一个"指针",说明编写一个对象的最佳方法是什么,该对象内部有一个指向另一个对象的指针?顺便说一句,这是我的临时代码,如果它有任何兴趣:

#include  <iostream>
#include  <fstream>
#include  <cstring>
#include  <cctype> 
#include  <cstdlib>
using namespace std;
const int MAXTXT = 80;
class Person {     
    protected:
        char* firstname;   
        char  birthdate[6]; 
    public:
        Person() {
            char fname[MAXTXT];
            cout << "First name: "; cin.getline(fname, MAXTXT);
            firstname = new char[strlen(fname + 1)];
            strcpy(firstname, fname);
            cout << "Birth date (DDMMYY): ";
            cin >> birthdate; cin.ignore();
            }
        void display() {
            cout << "nFirst name: " << firstname;
            cout << "nBorn: " << birthdate;
            }
        void writeToFile(ofstream & ut) {
            ut << firstname << "n" << birthdate;
            }
        };
class Adult: public Person {
    protected:
        char* lastname;
    public:
        Adult() {
            char lname[MAXTXT];
            cout << "Last name: "; cin.getline(lname, MAXTXT);
            lastname = new char[strlen(lname + 1)];
            strcpy(lastname, lname);
            }
        void writeToFile(ofstream & out) {
            out << "n" << lastname << "n";
            }
        void display() {
            cout << "nLast name: " << lastname;
            }
        };
class Partner: public Adult {
    private:
        int phone1;
        int phone2;
    public:
        Partner() {
            cout << "Phone (mobile): "; cin >> phone1;
            cout << "nPhone (job): ";  cin >> phone2; cin.ignore();
            }
        void writeToFile(ofstream & out) {
            Person::writeToFile(out);
            Adult::writeToFile(out);
            out << "n" << phone1 << " " << phone2;
            }
        void display() {
            Person::display();
            Adult::display();
            cout << "nPhone (mobile): " << phone1;
            cout << "nPhone (job): " << phone2;
            }
        };
class Employee: public Adult {      
    private:
        int      nr;                    
        char*    address;               
        Partner* partner;               
    public:
        Employee() {
            }
        Employee(int n) {
            char adr[MAXTXT];
            nr = n;
            cout << "Address: "; cin.getline(adr, MAXTXT);
            address = new char[strlen(adr + 1)];
            strcpy(address, adr);
            partner = NULL;
            }
        void changePartner() {
            Partner::Partner();
            }
        void writeToFile(ofstream & out) {
            Person::writeToFile(out);
            Adult::writeToFile(out);
            out << nr << "n" << address << endl;
            }
        void display() {
            Person::display();
            Adult::display();
            cout << "nAddress: " << address;
            if(partner) {
                partner->display();
                }
            }
        int returnEmpNr() {
            return nr;
            }
        };
Employee* employees[100];
int lastUsed = 0;
int main() {
    }
void writeToFile() {
    ofstream outfile("EMPLOYEES.DAT");
    ofstream outfile2("PARTNERS.DAT");
    outfile << lastUsed << "n";
    for(int i = 1; i <= lastUsed; i++) {
        employees[i]->writeToFile(outfile);
        }

指针除了对程序的单次运行之外毫无意义,如果指针在值处超出范围,则在读取文件时很可能毫无意义。Partner假设已经为它分配了空间,那么下一次的几率可能与 18,446,744,073,709,551,616 中的 1 一样糟糕,并且出错通常会造成致命的结果。这些致命的结果意味着你很幸运。您可能会破坏属于其他东西的完全有效的内存,并导致奇怪的、未定义的、比彻底崩溃更难调试的行为。

在C++指针通常是一个傻瓜赌注。 将它们用作最后的手段,因为它们确实可以增加您需要编写的代码量。

我推荐两个列表(但不一定是两个文件。两个列表都可以很容易地存在于一个文件中)一个是Partner s,一个是Employee s。Partner似乎不需要了解Employee,所以省去一些麻烦,先写出来并在合作伙伴列表中阅读。

编写Employee列表时,不要存储Partner指针,因为它不起作用。而是将Partner的索引存储在Partner列表中。然后当你阅读Employee列表时,你可以读取PartnerPartner表中的位置,查找该Partner,并指向它们。这就是为什么首先编写和阅读Partner要容易得多的原因;很难在尚未读取的列表中查找数据。

或者完全抛弃Partner指针的概念,并始终使用索引来查找Partner。这是更安全的方法,只要您始终将新合作伙伴附加到列表中,并且永远不要插入列表或做一些愚蠢的事情,例如打乱列表。

当我们弄乱指针时,请仔细阅读"什么是三法则?",因为您正在陷入内存管理大屠杀的泥潭。

正如每次复制Employee时所写,您将获得另一个愚蠢复制的Employee。它复制指针,而不是内容,因此您现在有 2 个Employee对象指向相同的 name s 和 Partner s。当你释放分配给partnername的内存时,你没有,而且真的,真的应该,另一个副本指向你的程序不再拥有的内存,并成为一个滴答作响的定时炸弹,等待你的程序崩溃。

使用std::vector<Partner>(注意它是Partnervector,而不是Partner *。这允许vector拥有和管理您的所有内存,而不仅仅是列表所需的内存)和索引清除了Partner的问题,因为std::vector为您管理内存,但名称仍在等待终止程序。用std::string替换char *将解决这个问题,还可以通过将内存管理负担从代码转移到 1990 年代某个时候为您编写的std::string,此后一直在数百万个程序中使用。20年后,没有多少虫子可以绊倒。

如果必须使用指针和指针数组,则需要创建自定义析构函数、复制构造函数、移动构造函数、赋值运算符和移动运算符。这是很多额外的工作。

但是这些vectorstring包含指针,您必须谨慎编写它们。这个主题,序列化,已经在其他地方被打死了,所以这里有一个指向一个信誉良好的网站的链接,它可能比我更好地处理它。