问题非常简单。为清楚起见,请考虑以下示例:
// Note that none of the class have any data members
// Or if they do have data members, they're of equal size, type, and quantity
class Foo {
public:
void foo1();
void foo2();
// 96 other methods ...
void foo99();
};
class Bar {
public:
// Only one method
void bar();
};
class Derived1 : public Foo { };
class Derived2 : public Bar { };
int main() {
Foo f;
Bar b;
Derived1 d1;
Derived2 d2;
return 0;
}
实例f
,b
,d1
和d2
是否都在内存中占用相同的空间?作为此问题的扩展,理论上复制Foo
传递实例的时间会超过Bar
吗?
答案 0 :(得分:25)
只有实例数据会增加类实例的大小(在我所知的所有实现中),除非你添加虚函数或从具有虚函数的类继承,那么你需要一次性命中v -table指针。
另外,正如其他人正确提到的,类的最小大小是1个字节。
一些例子:
// size 1 byte (at least)
class cls1
{
};
// size 1 byte (at least)
class cls2
{
// no hit to the instance size, the function address is used directly by calling code.
int instanceFunc();
};
// sizeof(void*) (at least, for the v-table)
class cls3
{
// These functions are indirectly called via the v-table, a pointer to which must be stored in each instance.
virtual int vFunc1();
// ...
virtual int vFunc99();
};
// sizeof(int) (minimum, but typical)
class cls4
{
int data;
};
// sizeof(void*) for the v-table (typical) since the base class has virtual members.
class cls5 : public cls3
{
};
编译器实现可以使用多个v-table指针或其他方法处理多个虚拟继承,因此这些也会影响类的大小。
最后,成员数据对齐选项可能会产生影响。编译器可能有一些选项或#pragma
来指定成员数据的起始地址应该是指定字节数的倍数。例如,对齐4字节边界并假设为sizeof(int) = 4
:
// 12 bytes since the offset of c must be at least 4 bytes from the offset of b. (assuming sizeof(int) = 4, sizeof(bool) = 1)
class cls6
{
int a;
bool b;
int c;
};
答案 1 :(得分:4)
严格地说,这是依赖于实现的。但是方法的数量不应该改变类对象的大小。对于非虚方法,对象内存中没有与方法指针相关的内容。如果您有虚方法,则每个对象都有一个指向vtable的指针。当您添加更多方法时,vtable会增长,但指针大小保持不变。
更多信息:对于非虚方法,编译器会跟踪每个类的方法指针。当您调用非虚方法时,编译器会将指向指向对象的方法的指针传递给隐藏参数或堆栈。这是方法“知道”其对象并访问this
指针的方式。对于虚方法,方法指针实际上是vtable的索引,因此编译器将this
传递给vtable中的解引用条目。
答案 2 :(得分:3)
是的,他们会的。实际上在你的情况下,大小将是1.在C ++中,即使没有任何数据成员的类也将具有1的大小。
答案 3 :(得分:1)
Foo
和Bar
每个都应该是一个字节。 Derived1
和Derived2
可能是一个或两个字节。
原因是编译器将所有静态信息存储在可执行代码中,包括所有成员函数。如果您的代码在foo1
的实例上调用Foo
,则只需调用Foo::foo1(this)
,这对于程序中的每个Foo
都是相同的。虚函数是一个例外,但是如果有任何虚函数,则不会为每个成员函数添加额外的大小,只增加一次额外的大小(通常是4/8字节)。