c++ - 构建动态分配的类对象数组

标签 c++ arrays

首先,如果你觉得这个问题非常简单,我想提前道歉,但我只是一个初学者。

我现在已经被这个问题困了大约一个星期了,它变得很荒谬,因为它不应该那么难,即使对于像我这样的初学者也是如此。

我正在编写一个程序,该程序从文本文件中读取有关收据的一堆信息,例如姓名、金额、日期等,然后将其打印到屏幕上。很简单,对吧?好吧,我开始在我的两个类 Transaction 和 TransactionsList 中使用静态数组并且它工作正常,我将文件的内容一行一行地打印到屏幕上。 现在我需要使用动态数组来做到这一点。

文本文件中的每一行都包含一个日期、类型、姓名、总和、 friend 的数量和这些 friend 的名字,这些应该被读取并存储为动态数组 trans 中的交易类对象。无论我在这个问题上做了多少理论和谷歌搜索,这都是我难以理解的。我应该在哪里使用重载赋值运算符,在哪里使用复制构造函数以及如何正确调用它们?我已经阅读了这些概念,但我仍然不能在我的程序中使用它们。这些问题现在就在我脑海中盘旋。

我已经将数组 friends 和 trans 更改为声明为指针,我理解这是正确的。然后我想用“new”为数组分配内存,但在这里我开始不确定我用 new 分配的位置,是在类的构造函数内部还是在需要它们的函数内部? 我知道 vector 是很多这些问题的答案,但我应该告诉你我还没有进入 vector ,所以我试图在没有 vector 的情况下解决这个问题。我意识到这可能有点倒退,但我应该能够构建我动态分配的对象数组并在我认为没有 vector 的情况下打印出来。我听说它们更实用,但现在我必须在没有 vector 概念的情况下理解这项任务。 我也阅读了浅拷贝和深拷贝之间的区别,并且了解了理论,但我就是无法以某种方式实现它。 (我知道我可能是弱智)。 这是我到目前为止所得到的:

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <iomanip>

using namespace std;

class Transaction
 {
  private:
   string date;
   string type;
   string name;
   double sum;
   int nr_friends;
   string *friends;

  public:
   Transaction();
   ~Transaction();
   Transaction &operator = ( const Transaction &t );
   string get_name();
   int get_no_friends();
   double get_sum();
   bool readOneTrans( istream &is );
   void writeOneTrans( ostream &os );
 };


class TransactionsList
 {
 private:
   Transaction *trans;
   int no_Trans;

 public:
   TransactionsList();
   ~TransactionsList();
   void read( istream & is );
   void print( ostream & os );
   void add( Transaction & t );

 };


int main()
{
    ifstream inFile("test.txt");
    Transaction t;
    TransactionsList tl;

   // t.readOneTrans(inFile);  // reading just one line works fine (when uncommented)
   // t.writeOneTrans(cout);  // printing works too just fine


    //tl.read(inFile); // here I want to read all contents of file

    //tl.print(cout); // and here print out them to the screen


return 0;

}


Transaction::Transaction()
    {
        date = "000000";
        type = "transp";
        name = "default";
        sum = 0.0;
        nr_friends = 0;
        friends = NULL;
    }

Transaction::~Transaction()
{
    delete [] friends;
}

Transaction &Transaction::operator = ( const Transaction &t )
{

        if ( this != &t )
        {
            delete[] friends;
            date = t.date;
            type = t.type;
            name = t.name;
            sum = t.sum;
            nr_friends = t.nr_friends;
            friends = new string[nr_friends];

            for ( int i = 0; i < nr_friends; i++ )
            {
                friends[i] = t.friends[i];
        }
    }


    return *this;
}

string Transaction::get_name()
    {
    return name;
}

double Transaction::get_sum()
    {
    return sum;
}

int Transaction::get_no_friends()
    {
        return nr_friends;
    }

bool Transaction::readOneTrans( istream &is )
    {
        is >> date >> type >> name >> sum >> nr_friends;

        friends = new string[nr_friends];

        for (int i = 0; i < nr_friends; i++)
            {
                is >> friends[i];
            }

        return is;
        return !is.eof();
    }

void Transaction::writeOneTrans( ostream &os )
    {
        os << left << setw(10) << date <<
        setw(10) << type << setw(10) << name
        << setw(10) << sum << setw(10)
        << nr_friends;

        for (int i = 0; i < nr_friends; i++)
            {
                os << left << setw(8) << friends[i];
            }

        os << endl;
    }



TransactionsList::TransactionsList()
{
        no_Trans = 1;
        trans = new Transaction[no_Trans];

}

TransactionsList::~TransactionsList()
{
    delete [] trans;
}

void TransactionsList::read( istream & is )
{
            Transaction t;

            while ( t.readOneTrans( is ))
                {

                    add( t );
                }

}

void TransactionsList::print( ostream & os )
{
    Transaction t;

    for (int i = 0; i < no_Trans; i++)
        {
            t = trans[i];
            t.writeOneTrans( os );
        }

    if (os == cout)
        {
            os << "\nNumber of transactions: " << no_Trans << endl;
        }

}

void TransactionsList::add( Transaction & t )
{
   // each time I read a line from the file it is passed in as object t here

   // here I want to add this object t to the dynamic array trans somehow
   // and keep building the array with a new class object every time

    // Probably by overloading assignment operator somehow but how?

        trans[no_Trans] = t;
        no_Trans++;

 // i have no idea what to put here to make it work...

}

如您所见,我想做的是不断地用 Transaction 类的不同对象构建动态数组 trans,每个实例代表我正在读取的文本文件中的不同行,以便我可以打印出来文件中的所有行最后都显示在屏幕上。 输出行应如下所示:

  011216    food      John       300       2        Nathan   Julia

现在要动态地执行此操作,我意识到我必须复制在方法“添加”中传入的对象 t 的内容并将其添加到数组 trans 并且以某种方式不丢失早期 t:s 的数据代表前面的文本行。当数组是静态数组时,这对我来说很容易做到,因为我只是将数组 trans 中的下一个元素指定为等于当前对象 t(在 add 函数内)。这是我的添加函数在静态数组中的样子:

 void TransactionsList::add( Transaction & t )
{
        trans[no_Trans] = t;
        no_Trans++;
}

显然,当您使用动态分配的内存时,这不起作用。我读了一些关于这个的理论,我知道一个人不能在运行时改变数组的大小所以实际上必须删除数组然后分配为一个更大的数组并使用深拷贝复制旧内容,这不会'不要只是复制动态数组的内存地址,而是用旧内容创建一个新数组。

如您所见,我已经阅读了很多理论,但并没有真正理解它... 谁能帮忙?我将非常感激,因为我在一周内没有学到任何东西,这现在真的让我很难受。我现在需要取得进步!

最佳答案

关于容器的一些提示:

  1. 不要使用 using namespace std; ( why? )

  2. C++ 中的无符号整数大小通常表示为 std::size_t来自 <cstddef> .

  3. 熟悉 rule of three/rule of three/four/five .

  4. 通常应用于此类的一个非常有用的习语是:' Resource Acquisition Is Initialization (RAII) '.

底线:

  1. 在管理资源的时候我们通常需要有

    • 析构函数
    • 复制构造函数
    • 移动构造函数
    • 复制赋值运算符
    • 移动赋值运算符
  2. 资源获取应该只发生在构造函数中。

    函数如add不应执行单独的资源获取,而应创建适当大小的临时资源并交换/移动内容。

关于c++ - 构建动态分配的类对象数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35038555/

相关文章:

c++ - 返回没有 std::function 的 lambda

c++ - Visual Studio c++ 链接器的一个很好的教程

java - Java 中的 getInteger

c# - 如何过滤数组以删除错误的值(如噪声)?

c++ - 如何开发跨平台的C++项目?

c++ - Boost::Regex 在长表达式不匹配时抛出错误

c++ - 为什么我们需要在这个模板函数实现中将求值表达式包装在 void(...) 内?

c - 二维数组元素不在 C 中保存值

java - 在文件数组中查找特定数据?

c++ - 如何创建 const 指针的动态数组?