读取c ++类对象

时间:2013-03-14 18:08:09

标签: c++

用于读取类对象(此处“ arts ”是对象的名称)。我必须遵循以下代码 filin是一个输入和输出流。

filin.write((char*)&arts,sizeof(arts));
filin.read((char*)&arts,sizeof(arts));

你能解释一下吗?

  1. 为什么我们通过添加(char *)以及为什么要使用字符指针来输入种姓。

  2. 为什么添加&艺术前的象征?。

  3. 为什么最后添加sizeof(arts)?

5 个答案:

答案 0 :(得分:3)

  

为什么我们通过添加(char *)以及为什么要使用字符指针来输入种姓。

char是一个错误的名字。这是谎言 - 它应该被称为byte,因为它就是这样的:字节。您正在使用的readwrite函数在字节缓冲区上工作 - 这是为了使它们成为通用的,即使用任意类型(尽管这也是谎言)。

  

为什么添加&艺术前的象征?

&获取对象的内存地址。通过编写(char*) &obj,我们实际上得到(地址)一个给定对象下面的字节缓冲区 - 换句话说,就是字节中对象的表示。

  

为什么最后添加sizeof(艺术)?

sizeof(obj)告诉我们内存中obj的大小 - 即它在字节缓冲区中占用多少字节。给定起始地址(参见前一点)和大小,我们完全表征对象在内存中的物理存在,我们可以使用它将对象从主存储器传输到文件中,反之亦然。

但是,正如我之前所说,这是一种谎言。 C ++实际上有许多类型的对象,它们不支持这种复制它们的内存,因为这些对象实际上对它们所处的内存做出了假设。在最简单的情况下,它们包含一个指针成员,在复制了字节表示之后对象,仍然指向旧位置,因此不再有用:

struct some_class {
    some_class* self;

    some_class() : self(this) { }
};

这个班有一个成员 - self - 指向自己。以字节方式复制此类的实例会破坏此标识并使对象无效(在复制副本的self成员后指向原始对象而不是副本)。

这种逐字节复制也称为浅拷贝 - 而不是拷贝,它会正确复制上述指针。

您展示的代码在C ++中通常不安全。事实上,它有更多的问题,而不是我到目前为止所提到的,并且在大多数情况下,对象的(反)序列化有更好的选择。

答案 1 :(得分:2)

您的问题的答案:

1 - writeread使用char指针(char *)。这意味着writeread逐字节工作,读取或写入的次数与函数的第二个参数给出的字节数完全相同。

2- &address of。这意味着您将获取arts的地址,然后您将地址转换为char指针(char*)&arts

3 - sizeof()返回其参数的长度(长度指的是内存中实例占用的大小)。在这种情况下,您获得arts的大小并告诉writereadwriteread的位数。

答案 2 :(得分:2)

首先,&运算符接受艺术对象的指针。假设您的对象arts的类型为Foo

Foo arts;

然后&arts的类型为Foo*

代码中的方法write()似乎处理字节数组(通常需要通过网络传输或写入文件),因此它使用指向char的指针(写为char*)因为类型char的大小为1个字节(好吧,在我所知道的任何平台上),所以如果你在char指针中加或减,你可以按前进或后退指针那个字节数(在C ++中,指针算术是以对象的字节大小的多个步骤完成的。)

当您从Foo*转换为char*时,您实际上是在告诉编译器将该指针视为1个字节的倍数,而不是对象完整大小的倍数。这是处理字节数组的函数的惯常做法,就像write()read()函数中的情况一样。

最后,在第一个参数中,只传递一个指针,一个内存地址。因此,要使函数write()知道它必须从指针读取多少字节,您必须传入对象的长度(第二个参数)。运算符sizeof(arts)在编译时转换为对象arts的大小(以字节为单位)(它也可以采用类型,因此如果{{1},写sizeof Foo将是等效的是Foo)的类型。

答案 3 :(得分:2)

从第二个问题开始更容易。 运营商&只需返回一个指向内存中对象的指针。然后我们将指向arts对象的指针转换为指向char的指针。 Char具有特定机器上最小可寻址存储器单元的大小,它可以是8位(最常见),越来越少。我们也称它为“字节”。最后我们调用sizeof函数,它返回对象的大小,表示为存储该对象所需的最小内存单元(在我们的例子中为chars)的数量。 之后该函数接收指向内存中某些位置的指针以及要写入或读取的字节数。它需要知道的一切。

答案 4 :(得分:1)

您发布的代码将对象存储在流中,然后从流中检索它。让我们将代码分解成碎片。

filin.write((char*)&arts,sizeof(arts));

首先,让我们检查一下write方法的签名。我想,它看起来类似于以下内容:

stream::write(char * input, int size)

因此,stream对象获取指向内存中某个位置的指针,从那里获取size个字节并存储。

现在,让我们将您的命令与此签名进行比较。 input是(char *)& arts。您有某种类型的arts对象,并且您想要存储它。 input必须是指向存储对象的内存中的指针,因此您可以使用&运算符&arts来检索它。但是,该方法期望inputchar*(意味着更少的指向字节的指针,不仅在您想要处理字符时使用char,而且还在您想要处理字节的位置使用char) ,但你的指针不是char *。这就是进行类型转换的原因:指向arts类型的指针被转换为指向char *的指针。它的价值保持不变,但现在编译器知道,知道你在做什么。

接下来,有一个size参数告诉流类要消耗多少字节。由于您要存储艺术对象,因此调用sizeof(arts)来验证其大小。