2012-08-01 21 views
10

Digamos que tengo dos clases:Herencia: ¿Función que devuelve el tipo propio?

class A 
{ 
    public: 
    A* Hello() 
    { 
     return this; 
    } 
} 

class B:public class A 
{ 
    public: 
    B* World() 
    { 
     return this; 
    } 
} 

Y digamos que tengo una instancia de la clase B así:

B test; 

Si llamo test.World()->Hello() que funcionaría bien. Pero test.Hello()->World() no funcionaría ya que Hello() devuelve A tipo.

¿Cómo puedo hacer que Hello() devuelva el tipo de B? No quiero usar una función virtual ya que tenemos más de 20 clases diferentes que heredan A.

+0

20 clases diferentes que heredan A no son tantas. Obtendrá 20 vtbls y un vptr por instancia (suponiendo que el envío virtual se realice de esa manera en su compilador). ¿Estás tan limitado de recursos que esto es realmente un problema? –

+1

Pereza. Al agregar un método dentro de la clase A, debería ir a todas las clases y agregar el mismo método. – Grapes

Respuesta

17

Puede utilizar CRTP, el patrón de plantilla curiosamente recurrente:

template<class Derived> 
class A 
{ 
    public: 
    Derived* Hello() 
    { 
     return static_cast<Derived*>(this); 
    } 
}; 

class B : public A<B> 
{ 
    public: 
    B* World() 
    { 
     return this; 
    } 
}; 


int main() { 
    B test; 
    test.World()->Hello(); 
    test.Hello()->World(); 
} 
+0

¡Gracias, esto es casi perfecto! ¿Todavía podría crear una instancia de A? Supongo que se vería así: una prueba ; – Grapes

+0

Solo tenga cuidado porque terminará con una copia separada de la clase A para cada clase que hereda de ella. Si @Grapes está preocupado por el uso del espacio, esto puede ser mucho peor que agregar un vtable para A. – Anton

0

Usted puede tener otro método Hola en B, incluso si no es virtual:

class A 
{ 
    public: 
    A* Hello() { return this; } 
} 

class B:public class A 
{ 
    public: 
    B* Hello() { return this; } 
    B* World() { return this; } 
} 
+0

Gracias Vaughn, estaba tratando de evitar eso ya que cada vez que agregas un nuevo método en la clase A, necesitarás pasar por todas las clases que heredan A y agregar el mismo método. Hay otra manera de hacer esto? – Grapes

+0

@Grapes: Creo que la respuesta de mfontanini es lo que estás buscando. –

+0

No funcionará porque no está anulando el método y cuando tiene el puntero 'A', se llamará 0 :: A :: Hello()' – Andrew

0

No es necesario para hacer Hello() devolver un B*. Hello() está devolviendo A* y todo lo que tiene que hacer es emitir su A* a B* para poder llamar al test.Hello()->World(). Por ejemplo:

B* b = dynamic_cast<B*>(test.Hello()); 
if(b != 0) b->World(); 
+0

Quiero encadenar mis llamadas como en el ejemplo, test-> Hello() -> World() -> FunctionFromA() -> FunctionFromB() -> FunctionFromA2() -> FunctionFromB() así que no estoy seguro de que esto trabaja bien para mí. – Grapes

Cuestiones relacionadas