2016-02-18 12 views
6

Come procedere all'integrazione di un metodo se una classe base non lo fornisce. Mi piacerebbe riutilizzare il metodo della classe base se fornito.Adattamento di una classe base fornita da un modello

Esempio:

#include <iostream> 
struct Base0 { }; 
struct Base1 { void m() { std::cout<<"Base1\n"; } }; 

template<typename T> 
struct Derived : public T { 
    //if T doesn't provide m, define it here, otherwise reuse the base class method 
    void m(){ /*? std::cout<<"Derived\n"; ?*/ } 
}; 

int main(){ 
    Derived<Base0> d0; 
    d0.m(); //should print "Derived" 
    Derived<Base1> d1; 
    d1.m(); //should print "Base1" 
} 
+0

Beh, se ti piace davvero a farlo in questo modo, si ha un problema con la chiamata ordina comunque. Derivato è il tipo e fin tanto che Derived ha una funzione 'm()' sovrascriverà sempre la funzione di base 'm()' –

+0

Stai mescolando concetti: ereditarietà, funzioni virtuali e modelli. Complessivamente è un odore di codice. Avere modelli, evitare l'ereditarietà e le funzioni virtuali. –

risposta

8

Con SFINAE, si può fare

template<typename T> 
struct Derived : public T { 
private: 
    template <typename U = T> 
    auto m_impl(int) -> decltype(std::declval<U&>().m()){ this->U::m(); } 

    template <typename U = T> 
    void m_impl(...) { std::cout<<"Derived\n"; } 

public: 
    void m() { m_impl(0); } 
}; 

Demo

2

Per essere generale, si dovrebbe definire la funzione in ogni caso sotto una firma diversa:

template<typename T> 
struct Derived : public T 
{ 
    auto m(std::false_type) { std::cout<<"Derived\n"; } 
}; 

Quindi è possibile utilizzare i metodi indicati nella this thread al fine di verificare se la classe base ha la funzione m():

template <typename...> 
using void_t = void; 

template <typename T, template <typename> class D, typename = void> 
struct detect : std::false_type {}; 

template <typename T, template <typename> class D> 
struct detect<T, D, void_t<D<T>>> : std::true_type {}; 

template <typename T> 
using has_m = decltype(std::declval<T>().m()); 

Infine, è possibile utilizzare che come

template<typename T> 
struct Derived : public T 
{ 
    auto m(std::true_type) { return T::m(); } 
    auto m(std::false_type) { std::cout<<"Derived\n"; } 
    auto m() { return m(detect</* const */ T, has_m>{}); } 
           ^^^^^^^^^^ 
           //if m() is const 
}; 

0

Come Aslay Berby già detto questo non è probabilmente il modo in cui si desidera andare. Se vuoi implementare qualcosa come i tratti o la progettazione basata su policy, il seguente codice potrebbe essere quello che stai cercando. In realtà tali disegni sono usati abbastanza comunemente e hanno anche un valore idiomatico.

#include <iostream> 
using namespace std; 

struct StandardTraits {void foo() {cout << "standard" << endl;}}; 

struct Traits1 {void foo() {cout << "traits1" << endl;}}; 
struct Traits2 {void foo() {cout << "traits2"<< endl;}}; 

template<typename T = StandardTraits> 
class SomeClass 
{ 
public: 
    typedef T Traits; 

    void useTraits() {traits.foo();} 

private: 
    Traits traits; 
}; 

int main() { 

    SomeClass<> x; 
    SomeClass<Traits1> y; 
    SomeClass<Traits2> z; 

    x.useTraits(); 
    y.useTraits(); 
    z.useTraits(); 

    return 0; 
} 

// output: 
// standard 
// traits1 
// traits2 

Consulta anche: https://en.wikipedia.org/wiki/Policy-based_design

Problemi correlati