【问题标题】:Read a data file containing objects of 2 diff. classes读取包含 2 个不同对象的数据文件。班级
【发布时间】:2013-11-27 07:37:32
【问题描述】:

我正在编写一个程序来管理书店的库存详细信息。它出售书籍及其录音带版本。我定义的类是:

class stock

{
char title[30],author[15];
float price; int stockpos;
char version[5];

protected:

void getdata(); void putdata();
void defvers(char a[])  {strcpy(version,a);}//used to identify book & tape
void rettitle(char a[]) {strcpy(a,title);}
void retauthor(char a[]){strcpy(a,author);}
void retvers(char a[])  {strcpy(a,version);}/* all these used to obtain title, 
author, and whether its a book/tape to compare with the given details while searching*/

};

在这里,我为通用数据成员和函数定义了一个类库,并派生了 2 个类 book 和 tape 用于定义唯一数据成员。

class book:public stock

{
int pagecount;

public:
book()   {  pagecount=0; defvers("book");    } //ctor
void getdata();
void putdata();

};

class tape:public stock

{
float duration; char readby[15];
public:
tape()    {  duration=0.00; defvers("tape");  }//ctor
void getdata();
void putdata();

};

我正在使用单个数据文件 stock.dat 并将书籍和磁带的详细信息存储到其中。

现在,让我感到困惑的是如何定义一个 stock 类函数,该函数将根据用户的选择从单个数据文件 stock.dat 中显示书籍或磁带的所有详细信息。鉴于书籍和磁带类都有不同的大小,我该如何操作 file.read()? 还是我走错了路,应该只创建 2 个单独的数据文件 books.dat 和 tapes.dat,而不在乎它会延长源代码?

请帮帮我。 〜阿西拉

编辑: 是的,我确实有一个字段来指定它是一本书还是一盘磁带。它在类股票中定义的“版本[5]”。对我来说,问题是派生类 book 和 tape 的对象,我用来写入二进制数据的文件具有不同的大小。

文件中的内容有点像:

书(大小 x) 书(x 号)

磁带(大小为 y)

书(x号)

胶带(大小为 y) 胶带(y号)

那我怎样才能只读取磁带对象并显示它们呢?

编辑:
感谢 Alwin、Pita 和 Retired Ninja 回答我的问题。您的意见对我来说非常有价值。我学到了很多东西,并且对如何创建我的项目有了很多想法。我真的很感谢你花时间帮助我并耐心地回答我的问题。再次感谢大家。

【问题讨论】:

  • 您的文件是文本格式还是二进制格式?无论哪种方式,您都可以保存接下来要读取的对象类型,然后适当地处理它。
  • 问题已更新。请检查一下。
  • 好吧,我不知道你的文件是什么样子的,但希望你先写类型,这样就可以在不读取任何内容的情况下对其进行检查。如果您只想阅读磁带,您很可能需要阅读所有内容并丢弃您不想要的部分。如果每种类型的记录都是固定大小的,您也可以在确定它是您不需要的东西后尝试寻找它们,但仅仅阅读它可能会同样快,甚至更快。
  • 但问题是 book 类只包含一个额外的数据成员(int 类型),而 tape 类有 2 个 diff 数据成员(1 个 float 和 string 成员)。所以这两种对象都有差异。尺寸。如果我尝试使用 file.read((char*)&bookb, size of(bookb)); 读取磁带类的对象这不会引发错误吗?
  • 如果您将两者存储在同一个文件中,您将需要一种更复杂的序列化方法,而不仅仅是将每个结构保存/加载为 blob。

标签: c++


【解决方案1】:

如果您坚持将数据放在 1 个文件中,最好向您的数据添加一个名为“类型”的字段,用于标识该对象中存储的数据。

但我绝对建议将它放在两个不同的文件中,因为它会使许多事情变得更容易,也使代码看起来更好。

如果这是 C++,为什么不使用任何返回值?

【讨论】:

  • 我同意 Alwin Leering 的观点,即您尝试做的是编写数据库的低级代码,这不是一件容易的事。对于二进制文件,你不能做类似getLine() 在这里阅读c-faq.com/stdio/textvsbinary.html 只是好奇,这是一个学校项目吗?我的建议绝对是使用常规的 csv 文件而不是二进制文件来进行此类操作或使用 SQLite。
  • 是的,这是一个学校项目。我的 +1,+2 课程甚至没有提到 csv 文件,所以我对如何操作 csv 一无所知。它像文本文件吗?
  • @user3040670 csv文件是逗号分隔值,格式类似于电子表格,行用换行符分隔,列用逗号分隔
【解决方案2】:

如果您的书店在您的程序的整个生命周期内只提供磁带和书籍,那么您一定要放轻松,创建两个文件。如果您预计您的书店将来会销售不同类型的商品,并且他们希望您扩展您的应用程序以考虑到这一点,那么您最好使用版本控制策略。

很大程度上取决于您如何在应用程序内部组织对象。您是在向量中保存对象还是在使用数组(从您在函数签名中使用char a[] 并使用 strcpy 的事实来看,我得到的明显印象是您是 C 编码器,因此会使用数组)。你是使用多个数组还是单个数组?

显示加载/存储函数的本质可能比这两个类更有指导意义,但基本理论是存储一些标记/标识符,然后是对象。当您读回文件时,您首先读取标记并创建相应类型的对象,之后您可以通过流式传输对象数据来初始化该对象。 另一种解决方案是首先流式传输一种类型的所有对象,然后是下一种类型的所有对象(中间有一个标记)

祝你好运。

[编辑]

您所描述的是低级数据库访问层实现。考虑到这个话题的难度,有很多薪​​水很高的程序员花费数年时间来正确和高效地完成这项工作。

所以要么这是一个学习练习,要么你走错了路。不要重新发明轮子并使用现有的东西。 鉴于您到目前为止告诉我的内容,我了解此应用程序的数据库将很小并且在低负载条件下运行。您还表示希望将数据存储在一个文件中。

我建议你研究一下 SQLite,一个免费的数据库访问层系统。您可以使用源代码来完成它,以便从中学习并融入您的程序中。

祝你好运

【讨论】:

  • 我正在使用数组来接收用户选择,如“书”“磁带”,并在搜索过程中提取作者等内容以进行比较。就像,retauthor() 会将存储在正在读取的对象中的作者的名称复制到字符串 rauthor 中,这样我就可以执行“如果当前读取的对象的 rauthor 等于用户给出的 sauthor,则显示该对象”。
  • 我将书籍和磁带作为单独的课程制作,因为磁带/有声读物的长度为给定分钟,并且由某人配音,这不适用于书籍。同样,有声读物也不会没有。页数,一本书。如果我让一个类同时代表书籍和磁带,那么对于一种类型,某些字段必须留空,我不确定是否允许这样做。
  • 我实际上不知道如何从文件中仅读取对象的特定成员,即使它是第一个 :( 我只知道使用 file.read 读取完整对象() 函数。如果我决定坚持使用单个文件并在前半部分存储书籍并在后半部分存储磁带,那么我该如何分隔两半?我可以通过编写一个空的或预定义的对象作为分隔符来做到这一点?
  • 重新发表您的第一条评论:只是为了让我在脑海中清楚......书籍和磁带的列表,它们是仅在文件中还是存储在内存中。换句话说,如果您要查找某个作者的书,是否必须搜索磁盘文件,加载每个对象并进行比较?
  • 第二条评论,是的,C++ 类中允许空(未初始化或默认初始化)字段,就像 C 中的结构可以有一个包含垃圾的字段成员。第三条评论:标签不需要是你班级的成员。您可以将任何内容写入文件,甚至是标签字符串。
【解决方案3】:

好的,让我们从头开始。由于这是一个学校项目,记录的数量将非常少。所以你可以做的就是将完整的文件读入内存。现在你要做的是在你的 stock 类中有一个变量,表示它是一本书还是一盘磁带。

您定义一个指向第一条记录的股票指针并检查类型变量。您现在可以定义书本指针或磁带指针以指向同一内存位置。

您可以通过将股票指针向前移动派生类的大小来找到下一条记录。

这是非常粗略的,在现实世界的应用程序中永远不会存在,但它可能适用于您的学校项目。

顺便说一句,您似乎正在编写 C 代码并试图将其放入 C++ 夹克中。也许您会更自在地使用结构在 C 中编写应用程序。这可能会让您对事情更熟悉/更清楚。

祝你好运。

【讨论】:

    猜你喜欢
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 2016-12-08
    相关资源
    最近更新 更多