2010-12-24 4 views
5

Considere el siguiente segmento de código:Comportamiento de objeto de C++ Referencia

class Window // Base class for C++ virtual function example 
    { 
     public: 
      virtual void Create() // virtual function for C++ virtual function example 
      { 
       cout <<"Base class Window"<<endl; 
      } 
    }; 

    class CommandButton : public Window 
    { 
     public: 
      void Create() 
      { 
       cout<<"Derived class Command Button - Overridden C++ virtual function"<<endl; 
      } 
    }; 

    int main() 
    { 
     Window *button = new CommandButton; 
     Window& aRef = *button; 
     aRef.Create(); // Output: Derived class Command Button - Overridden C++ virtual function 
     Window bRef=*button; 
     bRef.Create(); // Output: Base class Window 

     return 0; 
    } 

Tanto Aref y BREF se asignan * Botón, pero ¿por qué son los dos resultados distintos. ¿Cuál es la diferencia entre asignar a Tipo de referencia y Tipo de no referencia?

Respuesta

10

Ha encontrado el problema de rebanado.

Window bRef =*button; 

Aquí bRef no es una referencia sino un objeto. Cuando asigna un tipo derivado a bRef, corta la parte derivada dejándola con solo un objeto Window construido a partir de un CommandButton.

Lo que está sucediendo es que bRef se crea en la declaración anterior utilizando el constructor de copia generado por el compilador para la clase Ventana. Todo lo que este constructor hace es copiar los elementos miembros del RHS al objeto recién construido. Como la clase no contiene miembros, no ocurre nada.

En una nota al margen: una clase con miembros virtuales también debería tener un destructor virtual.

+0

Entonces, con este enlace de copiado tardío del constructor simplemente no sucede, ¿no? –

+0

Artillero: Encuadernación tardía no es relevante aquí. Está creando un nuevo objeto estáticamente estátizado, no un objeto de tipo dinámico (para eso necesita una referencia o un puntero). –

+0

destructor virtual o protegido. En muchos diseños, las funciones de miembro se llaman polimórficamente sin eliminar polimórficamente. –

2
Window bRef=*button; 
bRef.Create(); // Output: Base class Window 

El tipo estático, así como dinámica de bRef sólo es Window. El mecanismo virtual funciona solo con referencias y punteros. bRef es un objeto, no una referencia o un puntero.

1
Window bRef=*button; 
bRef.Create(); // Output: Base class Window 

Aquí bRef no es la referencia a button (que acaba de nombrar así). bRef obtiene solo el subobjeto base que es Window.

+0

Pero, ¿cuál es el efecto de esta tarea que estoy haciendo? Dado que el botón * se inicializó con CommandButton, ¿no debería ser entonces un error de compilación? –

+0

No. Su clase Window tiene una ventana de constructor de copias (const Window &). Como CommandButton es una ventana, puede ser el argumento para ese constructor de copia. – cgmb

+0

@ Slavik81: Sí, ¿entonces? ¿Cómo invalida lo que dije? – Nawaz

7
  • aRef tiene Windowestática tipo pero CommandButtondinámico tipo
  • bRef es simplemente un objeto de tipo Window (la CommandButton'parte' se perdió en la copia)

Esto se conoce comúnmente como object slicing y d usualmente se evita haciendo que las clases base sean abstractas (proporcionando una función virtual pura) o no copiables (por ejemplo, usando boost::noncopyable), porque cualquiera de las dos soluciones haría que el código no compilara en la línea Window& aRef = *button;.


Ahora, ¿por qué bRef.Create() llamada Window::Create? Bueno, no hay nada más que Window en bRef así que realmente no hay mucha alternativa. Esto es esencialmente como declarar un Window y llamar al Create: el hecho de que bRef se haya copiado de una instancia CommandButton es irrelevante porque la parte CommandButton se perdió en la copia.

Intentaré aclarar esto citando el estándar (10.3/6):

[Nota: la interpretación de la llamada de una función virtual depende del tipo del objeto para el cual es llamado (la dinámica tipo) , mientras que la interpretación de una llamada de una función de miembro no virtual depende solo en el tipo de puntero o referencia que denota ese objeto ( tipo estático) (5.2.2). ]

Solo a través de un puntero o indirección de referencia puede el tipo estático de un objeto diferir de su tipo dinámico.

Cuestiones relacionadas