class 如何知道其成员的大小?
How does a class know the sizeof its members?
为了在这里跳过一些重复并将问题缩小到更具体的范围,我将很快介绍我认为我理解的内容。
一个class是一个指针,指向不同大小的变量,称为成员。如果成员的大小不同,则它们都分配相同的 space 最大成员的大小。
因此在内存中它们的大小都相同,因此我的问题是:class 如何知道其成员的大小?
示例:
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时知道如何return short (99 0) 而不是 int (99 0 -1 70)?
class不需要知道,你的编译器知道。
If the members are of different sizes, they are all allocated the same space of the sizeof the biggest member.
这根本不是真的。想象一下 class 有两个成员,第一个是 20 个双打的大结构,第二个是一个字符。
这是编译器的任务,这就是为什么 class 在这种情况和类似情况下必须是完整类型的原因,即编译器需要这样:
struct foo {
short f;
int b;
};
...或类似的。当类型完成时,编译器可以决定类型的大小和它的字段的偏移量以及在某些情况下它需要知道的其他事情。
如果没有完整的类型定义,它将无法:
- 接受
foo
类型变量的声明(即 foo f;
语句)。
- 接受
sizeof(foo)
表达式
- 创建指向成员的指针。
- ...等等。
由于您无法在没有完整类型的情况下声明变量 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
。在 class 方法中,f
被命名为 this
.
class 的工作方式就是这样(而且它们还有一个 table 指向它们的虚函数的指针,当你调用一个时,你实际上是在调用第一个,第二个或 table 中的第三个函数)。单一继承的工作方式是所有基 class' 成员和方法首先出现在派生 class 中的相同偏移量处。多重继承的工作方式——很复杂。
为了在这里跳过一些重复并将问题缩小到更具体的范围,我将很快介绍我认为我理解的内容。
一个class是一个指针,指向不同大小的变量,称为成员。如果成员的大小不同,则它们都分配相同的 space 最大成员的大小。
因此在内存中它们的大小都相同,因此我的问题是:class 如何知道其成员的大小?
示例:
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时知道如何return short (99 0) 而不是 int (99 0 -1 70)?
class不需要知道,你的编译器知道。
If the members are of different sizes, they are all allocated the same space of the sizeof the biggest member.
这根本不是真的。想象一下 class 有两个成员,第一个是 20 个双打的大结构,第二个是一个字符。
这是编译器的任务,这就是为什么 class 在这种情况和类似情况下必须是完整类型的原因,即编译器需要这样:
struct foo {
short f;
int b;
};
...或类似的。当类型完成时,编译器可以决定类型的大小和它的字段的偏移量以及在某些情况下它需要知道的其他事情。
如果没有完整的类型定义,它将无法:
- 接受
foo
类型变量的声明(即foo f;
语句)。 - 接受
sizeof(foo)
表达式 - 创建指向成员的指针。
- ...等等。
由于您无法在没有完整类型的情况下声明变量 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
。在 class 方法中,f
被命名为 this
.
class 的工作方式就是这样(而且它们还有一个 table 指向它们的虚函数的指针,当你调用一个时,你实际上是在调用第一个,第二个或 table 中的第三个函数)。单一继承的工作方式是所有基 class' 成员和方法首先出现在派生 class 中的相同偏移量处。多重继承的工作方式——很复杂。