构建动态分配的类对象数组
Building a dynamically allocated array of class Objects
首先,如果这个问题对你来说非常容易,我想提前道歉,但我只是一个初学者。
这个问题我已经被困了大约一个星期,它变得越来越荒谬,因为它不应该那么难,即使对于像我这样的完全初学者也是如此。
我正在编写一个程序,该程序从文本文件中读取有关收据的大量信息,例如姓名,总和,日期等,然后将其打印到屏幕上。很简单,对吧?好吧,我开始在我的两个类事务和事务列表中使用静态数组,它工作正常,我将文件的内容打印到屏幕上,只是一行接着一行。现在我需要使用动态数组来执行此操作。
文本文件中的每一行都包含一个日期、类型、名称、总和、朋友的数量和那些朋友的名字,这些朋友应该被读取并存储为动态数组 trans 中的 Transaction 类对象。这就是我难以理解的地方,无论我在这个问题上做了多少理论和谷歌搜索。我应该在哪里使用重载的辅助运算符,在哪里使用复制构造函数以及如何正确调用它们?我已经阅读了这些概念,但我仍然无法在我的程序中使用它们。这些问题现在就在我脑海中飞来飞去。
我已经将数组 friends 和 trans 更改为声明为指针,我知道这是正确的。然后我想用"new"为数组分配内存,但在这里我开始不确定我在哪里分配新的,在它们的类的构造器内部还是在需要它们的函数中?我意识到向量是很多问题的答案,但我应该告诉你,我还没有进入向量,所以我试图在没有向量的情况下解决这个问题。我意识到这可能有点倒退,但我应该能够构建动态分配的对象数组并将其打印出来,而无需我认为的向量。我听说它们更实用,但现在我必须在没有向量概念的情况下理解这个任务。我也读过浅拷贝和深拷贝之间的区别,我明白了理论,但我无法以某种方式实现它。(我知道我可能是智障)。这是我到目前为止得到的:
#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
为了现在动态地执行此操作,我意识到我必须复制在方法"add"中传入的对象 t 的内容并将其添加到数组 trans 中,并且以某种方式不会丢失表示先前文本行的早期 t:s 的数据。这对我来说很容易做到,而数组是静态的,因为我刚刚分配了数组中的下一个元素 trans 等于当前对象 t(在 add 函数内)。这是我的 add 函数在静态数组中的样子:
void TransactionsList::add( Transaction & t )
{
trans[no_Trans] = t;
no_Trans++;
}
显然,当您使用动态分配的内存时,这不起作用。我读了一些关于这个的理论,我知道一个人不能在运行时更改数组的大小,所以数组实际上必须被删除,然后分配为一个更大的数组,并使用深层复制复制旧内容,这不仅复制动态数组的内存地址,而且使用旧内容创建一个新数组。
如您所见,我读过很多理论,但并不真正理解它......谁能帮忙?我将非常感激,因为我一周没有学到任何东西,这真的杀死了我。我现在需要进步!
关于容器的一些提示:
-
不要使用
using namespace std;
(为什么? -
c++ 中的无符号整数大小通常表示为
<cstddef>
std::size_t
。
熟悉三法则/三法则 /四法则/五法则。
通常应用于此类类的一个非常有用的习语是:"资源获取是初始化(RAII)"。
底线:
-
在管理资源时,我们通常需要拥有
- 析构函数
- 复制构造函数
- 移动构造函数
- 复制赋值运算符
- 移动赋值运算符
-
资源获取应仅在构造函数中进行。
add
等函数不应执行单独的资源获取,而应创建适当大小的临时资源并交换/移动内容。
构造动态分配数组的问题与构造对象本身的问题完全不同。
class TransactionList {
Transaction *trans;
size_t trans_size;
size_t no_Trans;
public:
TransactionList(size_t initial_size)
: trans(new Transaction[initial_size]),
trans_size(initial_size),
no_Trans(0)
{
}
~TransactionList()
{
delete[] trans;
}
// ...
};
就是这样。现有的 add() 方法没有什么不同。它仍然以完全相同的方式工作,因为数组实际上只是指向数组中第一个元素的指针,这里仍然如此。
但是您确实需要弄清楚当no_Trans
达到实际分配的trans_size
时该怎么做。这将是你的家庭作业。
但是,您可能想要做的是将其更改为Transaction *
对象的数组,并在将每个Transaction
添加到数组时动态分配它。这将需要额外的工作。
(这个答案不需要额外的知识,只需要对代码进行一点点更改)
构造函数中的事情变得很奇怪:
no_Trans = 1;
trans = new Transaction[no_Trans];
人们通常会为未来的元素留下一些空间来添加:
max_Trans = 100;
no_Trans = 0;
trans = new Transaction[max_Trans];
在add()
if (no_Trans >= max_Trans) { // no more space?
// make a new array that is as twice big as the old one
max_Trans = 2 * max_Trans;
Transaction new_trans = new Transaction[max_Trans];
// copy elements to the new array
for (int i = 0; i < no_Trans; i++)
new_trans[i] = trans[i];
// delete the old one and start to use the new one
delete[] trans;
trans = new_trans;
}
trans[no_Trans] = t;
no_Trans++;
当然max_Trans
也可以是 1,让它增长为 1、2、3、4......但这需要对每个添加操作进行new
,这是低效的。
- 将对象数组的引用传递给函数
- 如何使用Visual Studio 2017在C++中为参数化对象数组使用唯一指针
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 类对象数组的问题会导致崩溃
- Arduino C++在构造函数中用参数声明对象数组
- 使用对象数组对 SFML 进行动画处理
- C++ 对象数组堆栈溢出
- 如何将对象数组作为参数传递给模板
- 使用向量初始化参数化构造函数的对象数组
- 如何初始化对象数组?
- C++创建对象数组
- 在对象数组中搜索字符串并返回相应值的函数
- 有没有办法使用该类的构造函数初始化另一个类的私有部分内的对象数组?
- 如何在运行时在对象数组中动态追加新对象C++并打印它们
- 为什么我在声明对象数组时不能使用 -> 运算符?
- 编译时生成应在构造函数中创建的非 constexpr 对象数组
- 使用 C++ 创建对象数组
- 对象数组打印空白字符串
- 重载运算符 [] 用于从对象数组中给出特定索引
- 如何在 C++ 中使用提升属性树从 JSON 文件中读取对象数组