2011-11-26 10 views
7

Esto me sorprendió un poco, pero yo estaba jugando con algo de código y descubrió que, al menos en mi equipo, cuando una función acepta una clase padre por referencia y se pasa una instancia secundaria, que el problema de rebanado doesn' t ocurrir Para ilustrar:¿Pasar por referencia siempre evita el problema de corte?

#include <iostream> 

class Parent 
{ 
public: 
    virtual void doSomething() 
    { 
     using namespace std; 
     cout << "Parent::DoSomething" << endl; 
    } 
}; 

class Child : public Parent 
{ 
public: 
    virtual void doSomething() 
    { 
     using namespace std; 
     cout << "Child::DoSomething" << endl; 
    } 
}; 

void performSomething(Parent& parent) 
{ 
    parent.doSomething(); 
} 

int main(int argc, char** argv) 
{ 
    Child myChild; 

    performSomething(myChild); 

    return 0; 
} 

Esto muestra Child::DoSomething.

Como dije, estaba un poco sorprendido. Quiero decir, sé que pasar por referencia es como pasando punteros (pero estoy mucho más seguro a mi entender), pero no sabía que todavía tenía que mantener la bondad polimórfica al hacerlo.

Sólo quiero para asegurarse de que, es este supone que sucede o se trata de uno de esos "funciona en mi máquina" tipo de casos?

+0

Eso no es lo que es "rebanar". Además, ¿ese código incluso compila? ¿Qué es 'using std;'? –

+0

Significó que 'using namespace std'. Pensé que podía transmitir el mensaje, pero limpié el código para obtener un beneficio general para el sitio. – Anthony

Respuesta

9

El comportamiento que está viendo es el correcto. Así es como se supone que debe funcionar. Las referencias funcionan igual que los punteros.

+0

Gracias, eso es lo que pensé. Como mencioné, solo quería un control de cordura, así que no hice suposiciones inválidas. – Anthony

2

Sí, el enlace a una referencia habilita el enlace dinámico. Esto es causado por la diferencia del tipo dinámico de un objeto y su tipo estático.

Si usted toma su parámetro por valor, se convierte en una clase Parent. Aunque si pasa algo a través de una referencia o un puntero y llama a una función virtual, el tiempo de ejecución buscará el dynamic type o el most-derived type del objeto real al que se hace referencia.

3

Eso se supone que sucederá. Pasar por referencia es EXACTAMENTE como pasar indicadores: está haciendo lo mismo debajo del capó. No hay magia para esto; cada instancia de un objeto polimórfico tiene asociada una tabla de funciones virtuales. Mientras no copie nada, no va a perder esa información y las llamadas a su función virtual funcionarán de la manera que esperaban.

La razón por la que tiene problemas al pasar por valor es que usará el constructor de copia del tipo especificado en la firma de la función, por lo que termina con una instancia completamente nueva de la superclase.

11

"rebanar" se refiere a la incapacidad del constructor de copia de base para distinguir partidos tipo exacto de clases derivadas. La única forma de invocar el corte es invocar el constructor de copia base. Normalmente, esto se produce al pasar argumentos por valor, aunque otras situaciones pueden ser ideadas:

class Base { }; 
class Derived : public Base { }; 

void foo(Base); 

int main() 
{ 
    Derived x; 

    Base y = x; // flagrant slicing 
    foo(x);  // slicing by passing by value 
} 

Nunca se está haciendo tal cosa, por lo que no algún situaciones de rebanar.

+2

Mencione el constructor de copias cuando pase por valor es lo que hace que esta respuesta sea perfecta. – dani

Cuestiones relacionadas