2012-08-10 20 views
5

Veamos este código:Cómo llamar a la función virtual de la clase derivada a través del puntero de clase base

class CBase 
{ 
public: 
    virtual vfunc() { cout << "CBase::vfunc()" << endl; } 
}; 

class CChild: public CBase 
{ 
public: 
    vfunc() { cout << "CChild::vfunc()" << endl; } 
}; 

int main() 
{ 
CBase *pBase = new CBase; 
((CChild*)pBase)->vfunc(); // !!! important 
delete pBase; 
return 0; 
} 

La salida es:

CBase::vfunc() 

Pero yo quiero ver: CChild :: vfunc()

explícita ((CChild *) pBASE) arroja que escribir "CChild *". Entonces, ¿por qué llamar a vfunc derivado? Necesito reemplazar cadena "importante" con: ((CChild *) pBase) -> CChild :: vfunc();

Respuesta

6

Eso no es como funciona - esto es:

CBase *pBase = new CChild; 
pBase->vfunc(); 

virtual llamadas a funciones se resuelven de forma dinámica sobre los punteros & referencias (a menos que se llama al método explícitamente, como lo hizo). Lo que significa que no importa lo que le digas al compilador que es el puntero, buscará el método en la tabla de navegación. Que, en su caso, es el vftable de CBase.

5

No se puede. *pBase es un objeto de tipo CBase. No puede tratarlo como si fuera un CChild porque no es un objeto CChild.

Uso del puntero obtenido por el elenco de CChild* hace que el programa muestre un comportamiento indefinido.

+1

Entonces, ¿cómo entender Schildt H .: "un puntero de clase base también puede ser utilizado como un puntero a un objeto de cualquier clase derivada de esa base". – LEXX

+0

¿Y por qué funciona la cadena ((CChild *) pBase) -> CChild :: vfunc()? – LEXX

+0

@LEXX: Primero, debe grabar ese libro y obtener [un buen libro introductorio] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Sin embargo, lo que dice en esa cita es correcto. Un puntero de clase base ('CBase *') puede apuntar a un objeto de un tipo derivado de 'CBase' (como' CChild').Sin embargo, eso no es lo que has hecho: tu puntero de clase base apunta a un objeto de clase base. Si tuviera, por ejemplo, 'CBase * p = new CChild();', entonces 'p' sería un puntero de clase base que apunta a un objeto de una clase derivada. –

2

las otras respuestas hacen puntos importantes - para complementar: si de hecho se trata de un CChild (por ejemplo, es una referencia pasada como parámetro), entonces puede usar dynamic_cast para abatir. sin embargo, la alta confianza en dynamic_cast es a menudo una indicación de que su diseño ha salido mal.

detalle en el modelo se puede encontrar aquí: http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx

lo que el proceso implicaría la fundición del parámetro CBase-CChild través dynamic_cast, si la referencia es una CChild y dynamic_cast tiene éxito, entonces usted podría estar seguro de que está se trata de un CChild y puede usarlo de manera segura como CChild.

0

El problema aquí parece muy simple. CBase no puede actualizar mágicamente a CChild! Permítame reescribir su ejemplo y agregar algunos comentarios. Debe explicarse por sí misma ...

#include <iostream> 

class CBase { 
public: 
    virtual void vfunc() { std::cout << "CBase::vfunc()" << std::endl; } 
    virtual ~CBase(){} // Virtual destructor... extremely important! I'll let you figure out why as an excercise 
}; 

class CChild: public CBase { 
public: 
    void vfunc() { std::cout << "CChild::vfunc()" << std::endl; } 
    ~CChild(){} // Is this destructor called? When? Try adding some std::cout to each destructor 
}; 

int main() 
{ 
    CBase *ptr1 = new CBase; 
    CBase *ptr2 = new CChild; 

    ptr1->vfunc(); // ptr1 points to an instance of CBase. This is what's important!! 
    ptr2->vfunc(); // ptr2 points to an instance of CChild, which can be referenced to as a CBase 

    delete ptr1; 
    delete ptr2; 
} 

Salida:

CBase::vfunc() 
CChild::vfunc() 

PD: Me he dado cuenta de que estoy cerca de 5 años tarde a la fiesta, pero ya que me parece un valor educativo en este I' ¡Lo publicaré de todos modos!

Cuestiones relacionadas