【问题标题】:Problem with file handling part of C++ assignmentC++ 分配的文件处理部分的问题
【发布时间】:2020-09-04 11:32:34
【问题描述】:

这个函数应该负责在调用相应的函数以从用户帐户中存款或取款后更新文件。但它不能做到这一点。我已经尽可能多地检查了,所有其他功能似乎都在正常工作。我已将其追溯到程序似乎失败的特定行。

int pos = (-1) * static_cast<int>(sizeof(ac));
File.seekp(pos, ios::cur);

//File.write((char *)&ac, sizeof(BankAccount));
File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));

是的,这是该行的两个版本,因为我不完全了解它们中的任何一个是如何工作的。 (第一个版本是我的,第二行来自给我们的示例程序)

void makeDepositOrWithdraw(int option)
{
    int num;
    cout << "\nEnter account number: ";
    cin >> num;
    int amt;
    bool found = false;
    BankAccount ac;
    SavingsAccount save;
    fstream File;
    File.open("Account.dat", ios::binary | ios::in | ios::out);
    if (!File)
    {
        cout << "Cannot retrieve database right now. Try again later";
        return;
    }
    while (!File.eof() && found == false)
    {
        File.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
        if (ac.getAccountNo() == num)
        {
            ac.displayAcc();
            if (option == 1)
                save.makeDeposit();
            if (option == 2)
                save.makeWithdrawal();
            int pos = (-1) * static_cast<int>(sizeof(ac));
            File.seekp(pos, ios::cur);

            //File.write((char *)&ac, sizeof(BankAccount));
            File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));

            cout << "__________________________________"
                 << "\nRecord updated ";
            found = true;
        }
    }
    File.close();
    if (!found)
        cout << "Record not found";
}

编辑:我很抱歉无法解释这一点。新帐户的初始创建有效。但是尝试进行额外的存款不会遇到任何错误,变量正在被正确更新到主要的BankAccount 类。但是 .dat 文件中的现有帐户中没有任何更新。程序仍然执行,没有任何错误。 我假设如果我了解存款部分的问题,我也可以解决提款问题,因为两者都是在同一个函数中处理的。

#include <iostream>
#include <fstream>
#include <cctype>
#include <iomanip>
using namespace std;

class BankAccount
{
private:
    float Balance, ServChargePerMonth, AnnualInterestRt, DepoAmt, WithdrwAmt;
    int NoOfDepositPerMonth, NoOfWithdrawalPerMonth, AccountNo;
    char Name[50], type;

public:
    virtual void makeDeposit()
    {
        Balance += DepoAmt;    //adding argument to acc bal
        NoOfDepositPerMonth++; //incrementing noOfDeposit
    };

    virtual void makeWithdrawal()
    {
        Balance -= WithdrwAmt;    //subtracting argument from acc bal
        NoOfWithdrawalPerMonth++; //incrementing noOfWithdrawal
    };

    virtual void createAcc()
    {
        cout << "\nEnter your account number: ";
        cin >> AccountNo;
        cout << "\nEnter your full name: ";
        cin.ignore();
        cin.getline(Name, 50);
        cout << "\nEnter the type of Account (C for current or S for savings): ";
        cin >> type;
        type = toupper(type);
        cout << "\nEnter initial deposit amount: ";
        cin >> Balance;
        cout << "___________________________________________________________"
             << "\n\nAccount created." << endl;
    };

    void displayAcc()
    {
        cout << "\nAccount number: " << AccountNo
             << "\nAccount holder name: " << Name
             << "\nType of account: " << type
             << "\nAccount balance: $" << Balance
             << "\nTotal number of deposits: " << NoOfDepositPerMonth
             << "\nTotal number of withdrawals: " << NoOfWithdrawalPerMonth
             << "\nService Charge: $" << ServChargePerMonth << endl;
    };

    //getters
    float getBalance() { return Balance; }
    float getDepoAmt() { return DepoAmt; }
    int getNoOfDeposit() { return NoOfDepositPerMonth; }
    int getNoOfWithdraw() { return NoOfWithdrawalPerMonth; }
    int getAccountNo() { return AccountNo; }

    //setters
    void setServChargePerMonth(float servCharge) //note: increasing, not setting
    {
        ServChargePerMonth += servCharge;
    }
    void setWithdrawAmt(float Amount)
    {
        WithdrwAmt = Amount;
    }
    void setBalance(float blnce)
    {
        Balance = blnce;
    }
    void setDepoAmt(float Amount)
    {
        DepoAmt = Amount;
    }
};
class CheckingAccount : public BankAccount
{
public:
    void makeWithdrawal(float WithdrwAmt)
    {
        if ((BankAccount::getBalance() - WithdrwAmt) < 0) //note: float doens't go below 0
            setBalance(getBalance() - 15.0);              //deducting $15
        else
            BankAccount::setWithdrawAmt(WithdrwAmt);
        BankAccount::makeWithdrawal();
    }
};
class SavingsAccount : public BankAccount
{
private:
    bool statusVar;
    bool status()
    {
        if (getBalance() < 25.0)
            statusVar = false;
        else
            statusVar = true;
        return statusVar;
    }

public:
    //setter
    void setStatus(bool statusVar)
    {
        statusVar = status();
    }
    bool getStatus() { return statusVar; }

    void makeWithdrawal()
    {

        if (status()) //check if active
        {
            cout << "Enter the amount you would like to withdraw today: ";
            float WithdrwAmt;
            cin >> WithdrwAmt;
            CheckingAccount temp;
            temp.makeWithdrawal(WithdrwAmt); //perform the reqd. check, as well as call the base ver.
        }
        else
        {
            cout << "Your account has deactivated. Please increase "
                 << "your balance to reactivate your account.";
        }
    }

    void makeDeposit()
    {
        cout << "Enter the amount you would like to deposit today: ";
        float temp;
        cin >> temp;
        setDepoAmt(temp); //setting value for amt of deposit
                          //check previous balance
        if (!status())    //if <$25,
        {                 //reactivate the acc. if depoAmt brings bal to $25
            if ((getBalance() + getDepoAmt()) >= 25.0)
                setStatus(true);
        }
        //check
        BankAccount::makeDeposit(); //and then call the base ver.
    }
};

void createAcc()
{
    BankAccount ac;
    ofstream writeFile;
    writeFile.open("Account.dat", ios::binary | ios::app);
    ac.createAcc();
    writeFile.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
    writeFile.close();
}

void makeDepositOrWithdraw(int option)
{
    int num;
    cout << "\nEnter account number: ";
    cin >> num;
    int amt;
    bool found = false;
    BankAccount ac;
    SavingsAccount save;
    fstream File;
    File.open("Account.dat", ios::binary | ios::in | ios::out);
    if (!File)
    {
        cout << "Cannot retrieve database right now. Try again later";
        return;
    }
    while (!File.eof() && found == false)
    {
        File.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
        if (ac.getAccountNo() == num)
        {
            ac.displayAcc();
            if (option == 1)
                save.makeDeposit();
            if (option == 2)
                save.makeWithdrawal();
            int pos = (-1) * static_cast<int>(sizeof(ac));
            File.seekp(pos, ios::cur);

            //File.write((char *)&ac, sizeof(BankAccount));
            File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));

            cout << "__________________________________"
                 << "\nRecord updated ";
            found = true;
        }
    }
    File.close();
    if (!found)
        cout << "Record not found";
}

void display()
{
    int num;
    cout << "\nEnter account number: ";
    cin >> num;
    bool flag = false;
    BankAccount ac;
    ifstream inFile;
    inFile.open("Account.dat", ios::binary);
    if (!inFile)
    {
        cout << "Cannot retrieve database right now. Try again later";
        return;
    }
    cout << "\nBALANCE DETAILS\n";
    while (inFile.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount)))
    {
        if (ac.getAccountNo() == num)
        {
            ac.displayAcc();
            flag = true;
        }
    }
    inFile.close();
    if (!flag)
        cout << "\nAccount number does not exist";
}

void deleteAcc()
{
    int num;
    cout << "\nEnter account number: ";
    cin >> num;
    BankAccount ac;
    ifstream inFile;
    ofstream outFile;
    inFile.open("Account.dat", ios::binary);
    if (!inFile)
    {
        cout << "Cannot retrieve database right now. Try again later";
        return;
    }
    outFile.open("temp.dat", ios::binary);
    inFile.seekg(0, ios::beg);
    while (inFile.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount)))
    {
        if (ac.getAccountNo() != num)
        {
            outFile.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
        }
    }
    inFile.close();
    outFile.close();
    remove("Account.dat");
    rename("temp.dat", "Account.dat");
    cout << "__________________________________________"
         << "Your account has been closed.";
}

int main()
{
    char opt;
    int temp;
start:
    do
    {
        system("clear");
        cout << "\n1. Create new account"
             << "\n2. Make a deposit"
             << "\n3. Make a withdrawal"
             << "\n4. Balance enquiry"
             << "\n5. Close existing account"
             << "\n6. Exit"
             << "\n\nPlease select your option(1-6)" << endl;
        cin >> opt;
        system("clear");
        switch (opt)
        {
        case '1':
            createAcc();
            break;
        case '2':
            makeDepositOrWithdraw(1);
            break;
        case '3':
            makeDepositOrWithdraw(2);
            break;
        case '4':
            display();
            break;
        case '5':
            deleteAcc();
            break;
        case '6':
            cout << "Thank you for banking with us" << endl;
            break;
        default:
            cout << "\a" << endl;
            goto start;
            break;
        }
        cin.ignore();
        cin.get();
    } while (opt != '6');
}

【问题讨论】:

  • 除此之外,您对!File.eof() 的使用看起来像wrong,您应该在之前使用读取的内容检查读取是否成功。
  • 简单地将结构保存到文件并加载它们可能不起作用,特别是如果其中包含指针或非平凡类。请发帖Minimal, Reproducible Example
  • @MikeCAT 我不知道该怎么做。我应该发布整个代码吗?
  • @RiteshRajbhandari “我不知道该怎么做。”链接的文章中对此进行了很好的描述。 “我只是应该发布整个代码吗?”不,只有重现您的案例确切错误所必需的部分。
  • @RiteshRajbhandari 说明很清楚,删除不影响您看到的错误的代码,发布一个确实有您看到的错误的完整程序。在您的情况下,这只是 I/O 部分。问题是大多数初学者不具备这样转换代码的技能。

标签: c++ oop file-handling filehandle


【解决方案1】:

C++ 对可以使用二进制读写的对象类型进行了限制。它们是复杂的规则,但您的 BankAccount 对象的问题在于它具有虚函数,这意味着您不能使用二进制读写。

另一个问题是您有几种不同类型的对象,但您的代码只读写BankAccount 对象,而不是CheckingAccount 对象或SavingsAccount 对象。

所以写的代码不能工作。

这是一个常见的初学者错误。二进制读写的功能非常有限,但初学者尝试读写各种复杂的对象并期望它能够正常工作,但事实并非如此。

您需要重新设计在程序中执行 I/O 的方式。我不确定您的要求是什么,但放弃使用二进制 I/O 似乎是最简单的方法。

【讨论】:

  • 感谢您提供的信息。否则我真的不会想到这一点
  • @RiteshRajbhandari 如果你想使用二进制 I/O,那么你的类需要是所谓的POD-type,但正如我上面所说,我认为你将不得不放弃二进制 I/O
  • 但是我可以使用文本,对吗?这是我能做的吗? IO直接转成纯文本而不是二进制?
  • @RiteshRajbhandari • 文本可以工作,但可能需要更多考虑如何将文本输出到文件,以及如何解析文件中的文本。有很多方法可以做到这一点。无论您选择哪种方式,我都建议您保持简单易用。
  • 你说得对……它只是一长串文本。我的直接想法是为所有字段分配固定长度,并在以后使用某种指针访问它们。我得调查一下。感谢您的帮助!
猜你喜欢
  • 2014-01-15
  • 1970-01-01
  • 1970-01-01
  • 2011-09-22
  • 2017-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多