2012-08-01 12 views
10

Diciamo che ho due classi:Ereditarietà: funzione che restituisce il tipo di auto?

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

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

E diciamo che ho un'istanza di B classe in questo modo:

B test; 

Se chiamo test.World()->Hello() che avrebbe funzionato bene. Ma test.Hello()->World() non funzionava dal Hello() restituisce il tipo A.

Come posso rendere Hello() restituire il tipo di B? Non voglio utilizzare una funzione virtual poiché abbiamo oltre 20 classi diverse che ereditano A.

+0

20 classi diverse che ereditano A non sono così tante. Finirai con 20 vtbl e un vptr per istanza (supponendo che l'invio virtuale sia fatto in quel modo sul tuo compilatore). Sei così a corto di risorse che questo è davvero un problema? –

+1

Pigrizia. Quando si aggiunge un metodo all'interno della classe A, si dovrebbe andare a tutte le classi e aggiungere lo stesso metodo. – Grapes

risposta

17

È possibile utilizzare CRTP, il modello modello curiosamente ricorrente:

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

Grazie, è quasi perfetto! Saresti ancora in grado di creare un'istanza di A? Sto assumendo che sarebbe simile a: Un test ; – Grapes

+0

Basta fare attenzione perché si finirà con una copia separata della classe A per ogni classe che ne eredita. Se @Grapes è preoccupato per l'utilizzo dello spazio, questo potrebbe essere molto peggiore dell'aggiunta di un vtable per A. – Anton

0

Si può avere un altro metodo Ciao in B, anche se non è virtuale:

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

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

Grazie Vaughn, stavo cercando di evitarlo poiché ogni volta che aggiungi un nuovo metodo in classe A, devi passare attraverso tutte le classi che ereditano A e aggiungere lo stesso metodo. c'è un altro modo per fare ciò? – Grapes

+0

@Grapes: Penso che la risposta di mfontanini sia ciò che stai cercando. –

+0

Non funziona perché non si esegue l'override del metodo e quando si ha il puntatore 'A'' A :: Hello() 'si chiamerà – Andrew

0

Non è necessario rendere Hello() restituire un B*. Hello() restituisce un A* e tutto ciò che devi fare è trasmettere il tuo A* a B* per poter chiamare test.Hello()->World(). Ad esempio:

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

Voglio concatenare le mie chiamate come nell'esempio, test-> Hello() -> World() -> FunctionFromA() -> FunctionFromB() -> FunctionFromA2() -> FunctionFromB() quindi non sono sicuro che questo sarebbe funziona bene per me – Grapes

Problemi correlati