2010-06-21 9 views
6

Tengo un puntero de clase base apuntando a un objeto de clase derivado. Llamo a la función foo() usando dos formas diferentes en el código a continuación. ¿Por qué se llama a Derived::foo() en el primer caso? ¿No debería llamar al (*obj).foo()Base::foo() función ya que ha sido desreferenciado?Llamada a funciones virtuales utilizando el objeto de desreferencia

class Base 
    { 
    public: 
     Base() {} 
     virtual void foo() { std::cout << "Base::foo() called" << std::endl; } 
     virtual ~Base() {}; 
    }; 

    class Derived: public Base 
    { 
    public: 
     Derived() : Base() {} 
     virtual void foo() { std::cout << "Derived::foo() called" << std::endl; } 
     virtual ~Derived() {}; 
    }; 

    int main() { 
     Base* obj = new Derived(); 
    // SCENARIO 1 
     (*obj).foo(); 
// SCENARIO 2 
     Base obj1 = *obj; 
     obj1.foo(); 

     return 0; 
    } 

Respuesta

15
// SCENARIO 1 
(*obj).foo(); 

Tenga en cuenta que

  1. obj es un nombre inapropiado aquí, ya que no se refiere a un objeto, sino a un puntero ,
  2. (*ptr).foo() es solo un tiovivo forma de hacer ptr->foo().

*ptr no da lugar a un objeto, pero en un referenciaBase& al objeto. Y una llamada de función virtual a través de referencia está sujeta a despacho dinámico, al igual que una llamada a través de un puntero.

// SCENARIO 2 
Base obj1 = *ptr; 
obj1.foo(); 

Lo que se hace aquí es que crear un totalmente nuevo objeto a través de slicing: sólo tiene las partes de la clase base de *ptr. Lo que quiere en su lugar es esto:

Base& ref = *ptr; 
ref.foo(); 
3

El escenario 2 crea un objeto completamente nuevo del tipo Base. Como tal, cuando hacemos obj1.foo(), el objeto no se deriva en absoluto; no hay forma de que llamemos a la función derivada.

En el escenario 1, sin embargo, el objeto es, en verdad, una instancia de Derived, al que estamos accediendo a través de un puntero Base. Esta es exactamente la situación para la cual las funciones virtuales están diseñadas; se usa la implementación de la clase derivada.

+0

Vale la pena describir las rebanadas. –

0

El polimorfismo funciona en las referencias (el resultado de desreferenciar un puntero) igual que en los punteros.

0

¿Qué quiere decir con "ya que se ha desreferenciado"?

El puntero de la clase base obj apunta al objeto de la clase derivada y, como ha declarado la función foo() virtual, se llamará a la clase derivada foo().

1

Ayuda si piensas un poco sobre la implementación. En el segundo escenario, en realidad está creando un nuevo objeto de tipo Base que vendrá con una nueva tabla de funciones virtuales. Pero en el primer escenario *obj "señalará", o más bien hará referencia, a un objeto que todavía tiene la tabla de funciones virtuales de un objeto de tipo Derivado.

0

(que es más bien extraña pregunta. Yo preferiría esperar que alguien pregunte por qué en el segundo caso Derived::foo no se llama.)

lenguaje

En C++, lo que se llama la versión de la función virtual es totalmente independiente de lo que tiene y lo que no ha sido "desreferenciado". Desreferencia no hace diferencia en absoluto. Lo único que importa es tipo dinámico del objeto utilizado en la llamada. En el primer caso se llama a Derived::foo porque el tipo dinámico del objeto *obj es Derived.

En el segundo caso, el tipo dinámico de obj1 es Base, por lo que se llama al Base::foo.

En otras palabras, todo funciona como se esperaba. Lo que hace que uno se pregunte si wat le hizo hacer su pregunta. ¿Qué te hizo esperar algo diferente?

1

En primer caso, la versión derivada de foo() se llamará debido a las razones obvias explicadas anteriormente. Además de otras respuestas, *(*Obj).func()* es sinónimo de *Obj->func()*.

En segundo caso un nuevo objeto de la clase Base se crean instancias a través del constructor de copia y ya que es un objeto de la clase Base se llamará la versión Base clase de foo().

Cuestiones relacionadas