类方法是否会增加类实例的大小?

Zee*_*bit 29 c++ methods memory-management class

问题非常简单.为清楚起见,请考虑以下示例:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

做实例f,b,d1,和d2所有占据内存空间相同数量?作为这个问题的延伸,理论上复制Foo传递它的实例需要的时间要长Bar吗?

Cod*_*key 26

只有实例数据才会增加类实例的大小(在我所知的所有实现中),除非你添加虚函数或从具有虚函数的类继承,那么你对v表指针进行一次性命中.

另外,正如其他人正确提到的那样,一个类的最小大小是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
{
};
Run Code Online (Sandbox Code Playgroud)

编译器实现可以使用多个v表指针或其他方法处理多个虚拟继承,因此这些也会影响类的大小.

最后,成员数据对齐选项可能会产生影响.编译器可能有一些选项或#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;
};
Run Code Online (Sandbox Code Playgroud)

  • @MooingDuck它必须在字节可寻址机器上至少有一个字节,因此两个对象不能具有相同的地址.编译器无法做出决定.(Stroustrup写了这个地方,这是我读到的地方,不记得在哪里.) (4认同)

Tho*_*eod 5

严格地说,这取决于实现。但是方法的数量不应更改类对象的大小。对于非虚拟方法,对象内存中没有与方法指针相关的内容。如果您有虚拟方法,则每个对象都有一个指向vtable的指针。当您添加更多方法时,vtable会增加,但指针大小保持不变。

更多信息:对于非虚拟方法,编译器会跟踪每个类的方法指针。当您调用非虚拟方法时,编译器会将指向该对象的方法的指针作为隐藏参数或堆栈传递给该对象。这就是方法“知道”其对象并访问this指针的方式。对于虚拟方法,方法指针实际上是vtable的索引,因此编译器将传递this到vtable中已取消引用的条目。