2014-08-28 10 views
11
#include <iostream> 

template<typename Impl> 
struct renderer{ 
    void get(){ 
     static_cast<Impl*>(this)->get(); 
    } 
}; 
struct open_gl : public renderer<open_gl>{ 
    void get(){ 
     std::cout << "OpenGL" << std::endl; 
    } 
}; 
struct direct_draw : public renderer<direct_draw>{ 
    void get(){ 
     std::cout << "DX" << std::endl; 
    } 
}; 
template<typename T> 
void print_renderer(renderer<T> r){ 
    r.get(); 
} 
int main() { 
    auto gl = open_gl(); 
    auto dx = direct_draw(); 
    print_renderer(gl); 
    print_renderer(dx); 
} 
  1. Perché non è possibile modificare il parametro di print_renderer a void print_renderer(const renderer<T> &r)? cannot convert 'this' pointer from 'const renderer<open_gl>' to 'renderer<open_gl> &' `polimorfismo statico in C++

  2. Perché ottengo un errore di runtime quando rinominare il metodo get in open_gl da arrivare a get1? Non dovrebbe questo innescare un errore del compilatore? Error = Stack overflow

** Nota Sto usando l'ultima MSVC

+1

E ... mix-n-partita! http://coliru.stacked-crooked.com/a/25722fa147efbbd3 –

risposta

12

1) Perché get non è una funzione const membro: non può fare la promessa di non modificare l'argomento (const).

Si potrebbe dichiarare get come const, e compila bene:

void get() const { ... } 

2) Il metodo di base get saranno chiamati, andando in una ricorsione infinita: overflow dello stack.

Se si dichiara la funzione override (ha bisogno di essere virtuale), il compilatore genera un errore se non effettivamente l'override un metodo di base:

void get1() override { ... } // Compiler error 
void get() override { ... } // Ok 

Nota:

Il titolo è "Polimorfismo statico in C++", ma penso che abbiate frainteso cos'è il polimorfismo statico: non (deve) fare uso dell'ereditarietà (come avete fatto voi). Piuttosto, i modelli di digitazione in fase di compilazione dei template risolveranno staticamente le chiamate di funzione per te.

Cioè, non hai bisogno di tipi correlati, non è necessario la classe base renderer a tutti, e si può semplicemente fare quanto segue (in questo caso, la ridenominazione di get1sarà causare un errore di compilazione) :

#include <iostream> 

struct open_gl { 
    void get(){ 
     std::cout << "OpenGL" << std::endl; 
    } 
}; 
struct direct_draw { 
    void get(){ 
     std::cout << "DX" << std::endl; 
    } 
}; 

template<typename T> 
void print_renderer(T r){ 
    r.get(); 
} 

int main() { 
    auto gl = open_gl(); 
    auto dx = direct_draw(); 
    print_renderer(gl); 
    print_renderer(dx); 
} 

Live demo

+0

Grazie, per la mia seconda domanda. È possibile lanciare un errore del compilatore quando 'get' non è implementato? Qualcosa come l'override? –

+0

@MaikKlein si veda la mia modifica – quantdev

+0

Come posso rendere 'void get()' virtuale se voglio il polimorfismo statico? –

5
  1. Becuase get non è contrassegnato const.
  2. Poiché il metodo della classe base viene utilizzato (irrilevante rispetto al cast) e passa al ciclo infinito.