6

Perdón por el título complicado. Tengo algo como esto:Matriz de objetos de clase base polimórficos inicializados con objetos de clase secundarios

class Base 
{ 
public: 
    int SomeMember; 
    Base() : SomeMember(42) {} 
    virtual int Get() { return SomeMember; } 
}; 

class ChildA : public Base 
{ 
public: 
    virtual int Get() { return SomeMember*2; } 
}; 

class ChildB : public Base 
{ 
public: 
    virtual int Get() { return SomeMember/2; } 
}; 

class ChildC : public Base 
{ 
public: 
    virtual int Get() { return SomeMember+2; } 
}; 

Base ar[] = { ChildA(), ChildB(), ChildC() }; 

for (int i=0; i<sizeof(ar)/sizeof(Base); i++) 
{ 
    Base* ptr = &ar[i]; 
    printf("El %i: %i\n", i, ptr->Get()); 
} 

que da salida:

El 0: 42 
El 1: 42 
El 2: 42 

¿Es este comportamiento correcto (en VC++ 2005)? Para ser honesto, esperaba que este código no se compilara, pero lo hizo, sin embargo, no me da los resultados que necesito. ¿Es esto posible?

Respuesta

8

Sí, este es el comportamiento correcto. La razón es

Base ar[] = { ChildA(), ChildB(), ChildC() }; 

inicializa elementos de la matriz mediante la copia de objetos en tres clases diferentes de objetos class Base y que produce objetos de class Base y por lo tanto observar el comportamiento de class Base de cada elemento de la matriz.

Si desea almacenar objetos de diferentes clases, debe asignarlos con new y almacenarlos en ellos.

+5

* Objeto rebanado *, como se lo conoce. – john

+0

Entonces, ¿copiar objetos sin copiar sus VTables? – GhassanPL

+0

@Kronikarz: Inicializa objetos de la 'clase Derivada 'copiando contenidos de otras clases en ellos. Por supuesto, no copia los vtables, son inmutables. – sharptooth

2

Para lograr un comportamiento polimórfico que esperaba, usted debe usar una matriz de punteros a Base y crear objetos a través de new:

Base* ar[] = { new ChildA(), new ChildB(), new ChildC() }; 
+2

Pierdes la memoria, chico malo. –

0

Lo que está sucediendo es que:

  1. Dado que el tipo de ar [] es Base, 3 * sizeof (Base) cantidad de memoria asignada a ar.

  2. Dado que no ha declarado un constructor de copia explícito para Base, se llama al constructor de copia predeterminado de base que copia la parte "Base" de los objetos ChildA, ChildB y ChildC en los objetos Base contenidos en la matriz ar (El constructor de copia predeterminado es lo suficientemente inteligente como para no copiar bit a bit el puntero virtual de los objetos secundarios en el puntero virtual base).

  3. Los puntos de referencia virtuales ar [0], ar [1] y ar [2] apuntan a Base :: Consigue que se llame a Base :: Get.

El punto a tener en cuenta aquí es que la función a la que apuntará el puntero virtual de un objeto siempre se conoce antes de la ejecución.

En este caso, el tiempo de ejecución sabía de antemano que el arr consistía en objetos "Base", por lo que configuró su vptr para señalar a Base :: Get tan pronto como se almacenó la memoria.

Cuestiones relacionadas