2010-01-31 29 views
6

¡Señor respetado!cómo C++ implementa el polimorfismo internamente?

Debo decirle que lo que sé y lo que no sé sobre la pregunta hecha para que pueda abordar el área débil de mi comprensión.

sé que C++ implementa el polimorfismo utilizando el Vtable que es una matriz de punteros cada puntero apunta a la función virtual de la clase, cada clase en la jerarquía tiene un vtable. Ahora supongamos que tengo la siguiente clase

class person 
{ 
    char name[20]; 
public: 
    person(char* pname) 
    { 
     strcpy(name,pname); 
    } 

    virtual void show() 
    { 
     cout<<"inside person show method, Name: "<<name; 
    } 
}; 

class teacher:public person 
{ 
    int scale; 

    teacher(char*pname, int s):person(pname) 
    { 
     scale=s; 
    } 

    void show() 
    { 
     cout<<"inside the teacher show method, Scale: "<<scale; 
    } 
}; 

Supongamos ahora que escribo en el programa principal

person *ptr; 
ptr=new teacher(16,"Zia"); 
ptr->show(); 

Ahora estoy confundir en este punto, la llamada se dirige a la función de presentación de la clase base, ahora, ya que es una función virtual, por lo que, a su vez, llama a la función apropiada. Sé que estoy equivocado aquí. Estoy confundido de lo que sería la secuencia de llamadas. ¿Cuál es el papel de Vtable y cómo funciona, por favor, elabore.

+2

"Respected Sir"? ¿Seriamente? Debería ser "Señor respetado * s *!" ya que somos muchos ...;) Siempre me pregunto por qué algunos usuarios comienzan con honoríficos, es un poco arcaico. – Spoike

+0

Zia, aprenda la sintaxis de Markdown: http://stackoverflow.com/editing-help – avakar

+0

@Zia ur Rahman: eche un vistazo al qn http://stackoverflow.com/questions/2092283/how-functions-are-resolved compilador por compilación, que explica cuándo el compilador hace una llamada polimórfica y cuándo va a ser una llamada directa. –

Respuesta

6

creo que debe llamar la atención sobre el libro de Stanley B. Lippman "Inside C++ object model".

deja mirada de presentación interna para sus clases:

tabla virtual de la persona y maestro

|---------------| +---> |------------------------| 
| name   | |  | "type_info" for person | 
|---------------| |  |------------------------| 
|__vptr__person |--+  | "person::~person"  | 
|---------------|  |------------------------| 
person p;    | "person::show"   | 
         |------------------------| 

|----------------| +---> |-------------------------| 
|person subobject| |  | "type_info" for teacher | 
|----------------| |  |-------------------------| 
|__vptr__teacher |--+  | "teacher::~teacher"  | 
|----------------|  |-------------------------| 
teacher t;    | "teacher::show"   | 
          |-------------------------|    

En general, no sabemos el tipo exacto de las direcciones de objetos PTR en cada invocación de espectáculo(). Sin embargo, sí sabemos que a través de ptr podemos acceder a la tabla virtual asociada con la clase del objeto.

Aunque no se sabe qué instancia de show() para invocar, sabemos que la dirección de cada instancia está contenida en la ranura 2.

Esta información permite al compilador para transformar internamente la llamada en

(*ptr->vptr[ 2 ])(ptr); 

En esta transformación, vptr representa el puntero de tabla virtual generado internamente insertado dentro de cada objeto de clase y 2 representa el intervalo asignado de show() dentro de la tabla virtual asociada con la jerarquía de puntos. Lo único que tenemos que hacer en tiempo de ejecución es calcular el tipo dinámico de ptr (y vtable apropiado) usando RTTI.

+0

Él no hizo su destructor virtual aunque –

+0

Sí. Creo que el aswer de Zia ur Rahman sería: "Estimado señor, no es todo el código, solo publiqué el código que tiene problema";) –

+0

ooooo sí señor! tienes razón, publico solo código relacionado. porque la gente odia leer el código extenso. Y sí, tu respuesta es completamente útil, gracias. –

8

Desde show se declara virtual en la clase person, el compilador no es difícil de código la llamada al método que iba a hacer por un método no virtual, será lugar compilar una búsqueda en la V-mesa con el fin de recuperar la función correcta.

Así ptr->show() se compilará como ptr->vtable['show']() que significa "buscar el puntero de función que corresponde al método show y ejecutarlo".

Dado que en tiempo de ejecución, ptr puntos a un objeto de clase teacher, la ranura vtable para show contiene un puntero al método show en la clase teacher. Es por eso que se ejecuta el método correcto.

En realidad, la búsqueda en la tabla V no se realiza mediante cadenas, sino que utiliza identificadores numéricos de métodos para que sea lo más rápido posible.

4

El lenguaje C++ no define las implementaciones de polimorfismo, ni siquiera el vtable. Eso depende de los compiladores.
Una implementación posible es la mencionada por Vincent Robert.

3

El estándar no dice nada sobre cómo implementar el polimorfismo. Una clase uno vtbl y un objeto uno vptr es la forma más popular. Espero que el siguiente pseudocódigo sea útil.

typedef struct { 
    void (*show)(void* self); 
    // more 

} person_vtbl; 

typedef struct { 
     person_vtbl* vtbl; 
     char   name[20]; 
} person; 

void person_show(void* self) { 
     cout<<"inside ... "<<static_cast<person*>(self)->name; 
} 
// more 

static person_vtbl person_vtbl_ = { &person_show }; // vtbl for person class 

void person_ctor(void* self, char const* name) { 
     person* p = static_cast<person*>(self); 
     strcpy(p->name, name); 
     p->vtbl = &person_vtbl // vptr of person object 
} 

typedef struct { 
    person base; 
    int scale; 
} teacher; 

void teacher_show(void* self) { 
     cout<<"inside the tearch ... "<<static_cast<teacher*>(self)->scale; 
} 
static person_vtbl teacher_vtbl_ = { &teacher_show }; 

void teacher_ctor(void* self, char const* name, int s) { 
     teacher* t = static_cast<teacher*>(self); 
     person_ctor(&t->base, name);  // construct base part 
     t->scale = s;     // construct teacher part 
     t->vtbl = &teacher_vtbl_;  // vptr of teacher object 
} 

// construct teacher : 
// person* ptr = new teacher("Zia", 16); 

teacher* tmp = static_cast<teacher*>(malloc(sizeof *tmp); 
teacher_ctor(tmp, "Zia", 16); // vptr of tmp points to teacher_vtbl_ 
person* ptr = &tmp->base; 

// call virtual function though pointer 
// ptr->show() 

ptr->vptr->show(ptr); // call teacher_show(ptr);