一个类如何知道其成员的大小?

How does a class know the sizeof its members?

本文关键字:成员 何知道 一个      更新时间:2023-10-16

为了跳过这里的重复,将问题缩小到更具体的范围,我将非常快速地介绍一下我认为我理解的内容。

类是指向不同大小的变量(称为成员)的指针。如果成员大小不同,则按最大成员的大小分配相同的空间。

所以在内存中它们都是相同的大小,因此我的问题:一个类如何知道其成员的大小?

的例子:

class foo
{
    short a = 99;
    int b = 88;
};
int main()
{
    foo f;
    for (int i = 0; i < sizeof(f); i++)
        cout << (int)((char*)&f)[i] << " ";
    return 0;
}
// Output:
// 99 0 -1 70 88 0 0 0
// 
// where -1 and 70 are random bytes in memory
对于那些不理解的人来说,f如何知道在读取成员a时如何返回(99 0)而不是int (99 0 -1 70)?

类不需要知道,编译器需要知道。

如果成员大小不同,则按最大成员的大小分配相同的空间。

这是不正确的。想象一个有两个成员的类,第一个是有20个double类型的大结构体,第二个是单个char类型。

这是编译器的任务这就是为什么在这种情况下类必须是完整类型的原因在类似的情况下,编译器需要这个:

struct foo {
     short f;
     int b;
};

…或类似的。当类型完成后,编译器可以决定类型的大小和字段的偏移量,以及在某些情况下需要知道的其他事情。

如果没有完整的类型定义,它将无法:

  1. 接受foo类型的变量声明(即foo f;语句)。
  2. 接受sizeof(foo)表达
  3. 创建成员指针
  4. …等等。

因为你不能在没有完整类型的情况下声明变量f,你就不能获得它的大小或访问它的成员。

如果在另一边使用了不完整类型。这是编译器只看到的:

struct foo;

编译器不能做任何需要完整类型的事情,但它可以有指向foo的指针,但它不能查看它的内部,分配它或对它进行指针算术

您有一些误解,但是为了更好地理解,您可能会尝试在一些简单的结构体上使用<stddef.h>中的offsetof( typename, membername )宏。也许可以尝试打印offsetof( foo, a ), offsetof( foo, b ), (uintptr_t)&f(uintptr_t)&f.b,看看编译器如何在给定f的地址下找到f.b。在类方法中,f被命名为this

类的工作方式是这样的(另外,它们还有一个指向虚函数的指针表,当你调用一个虚函数时,你实际上是在调用该表中的第一个、第二个或第三个函数)。单继承的工作方式是,所有基类的成员和方法首先以相同的偏移量出现在派生类中。多重继承的工作方式很复杂。