2015-09-01 60 views
4

我正在做一個基類,它有一些方法,這些方法在派生類中使用。除了(protected)方法之外,此基類類似於抽象類,它定義了必須在派生類中實現的接口(即public)方法。但它並不打算用作多態基,而是它的衍生物將用作一些其他函數/函子的模板參數,這些函數/函數將調用接口方法。如何確保派生類實現特定的方法,保留標準佈局?

鑑於上述情況,我可以使用通常的方式來定義像使用純虛函數一樣的抽象類,但是存在這樣的問題:生成的派生類需要具有標準佈局。因此不允許虛擬功能。但是仍然會有很多衍生物,直到稍後纔會使用,我想讓編譯器檢查所​​需的所有方法是否都使用了正確的簽名(例如int Derived::f(double)而不是int Derived::f(float)是不允許的) 。

考慮到標準佈局的要求,這樣做會是一個好的方法嗎?

+2

也許奇怪的循環模板模式可以幫助。所以你的基類調用派生類的方法,但解析是在編譯時完成的。 –

+0

聽起來像概念。請參閱http://www.boost.org/doc/libs/1_58_0/libs/concept_check/concept_check.htm –

+0

@TobySpeight爲什麼你不使用「答案」框來編寫答案,而是使用評論? (@DieterLücking) –

回答

2

這裏的CRTP圖與static_assert接口調度程序內實現:

#include <iostream> 
#include <type_traits> 

template<class Derived> 
class enable_down_cast 
{ 
     typedef enable_down_cast Base; 
public: 
     // casting "down" the inheritance hierarchy 
     Derived const* self() const { return static_cast<Derived const*>(this); } 
     Derived*  self()  { return static_cast<Derived*  >(this); } 
protected: 
     // disable deletion of Derived* through Base* 
     // enable deletion of Base* through Derived* 
     ~enable_down_cast() = default; 
}; 

template<class FX> 
class FooInterface 
: 
    public enable_down_cast<FX> 
{ 
    using enable_down_cast<FX>::self; // dependent name now in scope 
public: 
    int foo(double d) 
    { 
     static_assert(std::is_same<decltype(self()->do_foo(d)), int>::value, ""); 
     return self()->do_foo(d); 
    } 
protected: 
    // disable deletion of Derived* through Base* 
    // enable deletion of Base* through Derived* 
    ~FooInterface() = default; 
}; 

注意的是,以上僅static_assert火災如果返回類型的接口和實現的不匹配。但是你可以用你想要的任何類型特徵來修飾這個代碼,並且在SO上有plenty of Q&As這樣寫類型特徵來檢查接口和實現之間的確切函數簽名匹配。

class GoodFooImpl 
: 
    public FooInterface<GoodFooImpl> 
{ 
private: 
    friend class FooInterface<GoodFooImpl> ; 
    int do_foo(double) { std::cout << "GoodFooImpl\n"; return 0; } 
}; 

class BadFooImpl 
: 
    public FooInterface<BadFooImpl> 
{ 
private: 
    friend class FooInterface<BadFooImpl>; 
    char do_foo(double) { std::cout << "BadFooImpl\n"; return 0; } 
}; 

int main() 
{ 
    GoodFooImpl f1;   
    BadFooImpl f2; 

    static_assert(std::is_standard_layout<GoodFooImpl>::value, ""); 
    static_assert(std::is_standard_layout<BadFooImpl>::value, ""); 

    f1.foo(0.0); 
    f2.foo(0.0); // ERROR, static_assert fails, char != int 
} 

Live Example on Coliru.請注意,派生類實際上是標準佈局。

相關問題