Pregunta

He creado una clase, llamada vir, con una función mover:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     void move(){}
};

(Se deriva de una clase con variables int x, int y y char sym) He derivado una clase de esto, llamada subvir:

class subvir:public vir
{
public:
     subvir(int a,int b,char s){x=a;y=b;sym=s;}
     void move();
};
subvir::move()
{
     x++;
     return;
}

Y luego creé una matriz de vir, y puse un subvir en ella

subvir sv1(0,0,'Q');
vir vir_RA[1]={sv1};

Pero cuando intento usar sv1.move ():

vir_RA [0] .move ();

Utiliza el movimiento vir ({}) en lugar del movimiento subvir ({x ++}). He intentado hacer que sv1 a vir y vir_RA a vir, y funciona, y también funciona cuando hago que ambos sean subvir, pero necesito que sean diferentes. Intenté hacer vir :: move () un virtual puro, pero luego obtengo un error al verificar la matriz. ¿Alguien sabe cómo puedo hacer que move () funcione cuando lo uso de la matriz?

¿Fue útil?

Solución

Necesita una matriz de punteros en este caso, en lugar de una matriz de instancias. Use vir * [] en lugar de vir []

Otros consejos

Se encuentra con un problema llamado corte . Use una serie de punteros, o algo como Boost.ptr_container .

La clase base debe tener las funciones virtual para obtener lo que desea, haciendo que estos resultados sean puros en una clase base abstracta, algo que no puede crear una instancia. Sin embargo, aún puede crear punteros / referencias a clases base abstractas y asignarles objetos de clase derivados. Tu clase base se representa mejor como:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     virtual void move(){}
};

Esto hace que la clase derivada move también sea virtual. Sin embargo, su definición de move carece de un valor de retorno y no se compilará. Prueba:

void subvir::move()
{
     x++;
     return;
}

Tenga en cuenta que necesita punteros (como se menciona en las otras respuestas) o referencias a clases derivadas para que el enlace dinámico funcione. Entonces, en lugar de una matriz de objetos vir , use una matriz de punteros de clase base:

vir* v[ 2 ] = { new subvir(0, 0, 'Q'), new subvir(10, -10, 'P') };

También deberías f Lea las siguientes secciones de C ++ FAQ Lite:

Dos cosas. La matriz es una matriz de vir, así que, por supuesto, usa vir :: move. move () no es un método virtual.

Pero lo más importante es rebanar. No puede poner subclases en una matriz. Si sizeof vir! = Sizeof subvir, la matriz no se alineará correctamente. Actualmente son del mismo tamaño. Pero qué pasa si no lo son.

Sí, básicamente el compilador no permite subclases en matrices porque Las matrices se inicializan firmemente para el tamaño de tipo y los subtipos tienden a para ser más grande que los padres y daría lugar a problemas si pudiera Inicializar matrices con valores de subtipo. Lo que realmente sucede es que el compilador primero asigna la matriz N * tamaño (base_type) bytes. Y luego copia los bytes de tamaño (base_type) de cada una de las inicializaciones objetos. si fueran de diferentes tipos, serían truncados, y podrían pasar cosas raras en tu código.

Permítame consolidar las respuestas anteriores.

En realidad hay dos problemas aquí. Una es rebanar. Está inicializando una matriz de virs con una copia de un subvir. En tales casos, el compilador corta la parte vir del subvir y la copia en la matriz, por lo que realmente solo obtiene objetos vir allí. Ahora, en su caso particular, subvir no tiene miembros de datos adicionales más allá de los de vir, por lo que el corte es algo degenerado y el objeto vir se parece mucho a un subvir. Sin embargo, vir y subvir son clases diferentes y el objeto en la matriz termina siendo un objeto vir y no un objeto subvir disfrazado de vir. Una forma en que la diferencia entre los dos se manifestaría prácticamente, incluso si ambos tuvieran los mismos miembros de datos, es si vir tuviera funciones virtuales sobrecargadas por subvir. En ese caso, el puntero de vtable en el objeto de la matriz apuntaría a vtable de vir, no a subvir. Por supuesto, sería aún más explícito si subvir contuviera miembros de datos adicionales que no se encuentran en vir.

El segundo problema es el polimorfismo. En el punto de uso (la llamada a move ()), el compilador piensa que está llamando al método move () de un objeto de tipo vir (ya que la matriz es una matriz de virs). (El compilador es, por supuesto, correcto al pensar que, debido al corte, degenerar como puede ser en este caso). Si en realidad hubiera sido un objeto subvir como usted pretendía, podría obtener subvir :: move () llamado haciendo move ( ) virtual en vir.

Para obtener el comportamiento deseado, podría usar una matriz de punteros (pero luego estaría operando directamente en sv1, no una copia de la misma, a menos que primero haya creado una copia e inicializado la matriz con un puntero a la copia).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top