2011-11-08 9 views
24

La pregunta es bastante directa. Para mayor claridad, consideremos el siguiente ejemplo:¿Los métodos de clase aumentan el tamaño de las instancias de clase?

// 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; 
} 

Haz casos f, b, d1 y d2 todos ocupan la misma cantidad de espacio en la memoria? Como una extensión de esta pregunta, ¿copiar instancias de Foo al pasarlo toma más de Bar, teóricamente?

+0

99 métodos? arrgh .. – Nim

+0

@Nim: Quería realmente transmitir el mensaje.;) – Zeenobit

Respuesta

21

Solo los datos de instancia aumentan el tamaño de las instancias de una clase (en todas las implementaciones que conozco), excepto que si agrega funciones virtuales o hereda de una clase con funciones virtuales, entonces toma un solo golpe por un puntero de tabla v.

Además, como otra persona menciona correctamente el tamaño mínimo de una clase es de 1 byte.

Algunos ejemplos:

// 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 
{ 
}; 

implementaciones del compilador pueden manejar la herencia virtual múltiple con múltiples punteros v-mesa u otros otros métodos, por lo que estos también tendrán efecto sobre el tamaño de las clases.

Finalmente, las opciones de alineación de datos de los miembros pueden tener un impacto. El compilador puede tener alguna opción o #pragma para especificar que los datos de miembro deben tener una dirección de inicio que es un múltiplo del número de bytes especificado. Por ejemplo, con la alineación en 4 límites de bytes y asumiendo 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; 
}; 
+0

Más cerca, pero los tipos vacíos generalmente toman al menos un byte. Hay pocos compiladores que harán estos menos de un byte. –

+4

@MooingDuck Tiene que ser al menos un byte en máquinas direccionables por bytes, de modo que dos objetos no puedan tener la misma dirección. El compilador no llega a decidir. (Stroustrup escribió esto en algún lugar que es donde lo leí, no recuerdo dónde). –

+0

@SethCarnegie: Sí, pero el estándar _also_ dice que el compilador puede romper todas las reglas siempre que realice las mismas llamadas a IO y sea volátil. lee/escribe en el mismo orden con los mismos parámetros, lo que permite a GCC a veces hacer objetos de menos de un byte, siempre que eso no cambie la ejecución del programa. –

4

En términos generales, esto depende de la implementación. Pero la cantidad de métodos no debería cambiar el tamaño de los objetos de clase. Para los métodos no virtuales, no hay nada dentro de la memoria del objeto que se relacione con los punteros del método. Si tiene métodos virtuales, entonces cada objeto tiene un solo puntero a un vtable. El vtable crece cuando agrega más métodos, pero el tamaño del puntero permanece igual.

Más información: para los métodos no virtuales, el compilador rastrea los punteros del método para cada clase. cuando llama a un método no virtual, el compilador pasa un puntero al método que apunta al objeto, ya sea como un parámetro oculto o en la pila. Así es como un método 'conoce' su objeto y tiene acceso al puntero this. Para los métodos virtuales, el puntero de método es en realidad un índice en el vtable, por lo que el compilador pasa this a la entrada desreferenciada en el vtable.

+0

para métodos no virtuales, el compilador rastrea los punteros del método para cada clase. ¿Es esto una compensación que Sacrifica tiempo para el espacio? – Djvu

+0

@Djvu, no, los métodos no virtuales son más eficientes en tiempo y espacio. – ThomasMcLeod

3

Sí lo harán. En realidad, en su caso, el tamaño será 1. En C++ una clase incluso sin ningún miembro de datos tendrá un tamaño de 1.

1

Foo y Bar cada uno debe ser de un byte. Derived1 y Derived2 pueden ser uno o dos bytes.

El motivo es que el compilador almacena toda la información estática en el código ejecutable, incluidas todas las funciones de los miembros. Cuando su código llame al foo1 en una instancia de Foo, simplemente llama a Foo::foo1(this), que es el mismo para cada Foo en el programa. las funciones virtuales son una excepción, pero no agregan tamaño adicional por función de miembro, solo un tamaño adicional de una sola vez (generalmente 4/8 bytes) si hay funciones virtuales en absoluto.

Cuestiones relacionadas