2012-07-26 177 views
1

是否有一些常見的方法來定義模板成員函數的接口?我想創建一些純粹的抽象基類,並聲明模板成員函數,這些函數應該在派生類中重寫。比我想要能夠通過接口調用派生類的功能。我知道虛擬模板成員函數是不允許的。所以直到現在我想出了以下解決方案(見下文)。我想知道的是,如果我的做法是不好的設計或者有一些更好的方式來實現自己的目標:模板成員函數的接口

編輯:我想實現是一個序列化系統(類似於提高::序列化) 。因此,我想有一個通用的基本接口功能序列化它可以用來保存和加載對象。調用* do_serialize *函數時,調用保存和加載的正確函數將由提供的派生歸檔類確定。

因爲我不確定我提供的解決方案,我想問問是否有更好的方法(或更簡單的方法)來實現我的目標?

的接口:

template<typename Derived> 
class Archive{ 
public: 
    virtual ~Archive() = 0 {} 

    template<typename T> 
    Archive& serialize(T t) { 
    Derived* derived = static_cast<Derived*>(this); 
    return derived->serialize_derived(t); 
    } 
}; 

template<typename Derived> 
class Writer : public Archive<Derived> { 
public: 
    virtual ~Writer() = 0 {} 

    template<typename T> 
    void write(const T& t) { 
    Derived* derived = static_cast<Derived*>(this); 
    derived->write_derived(t); 
    } 
}; 

template<typename Derived> 
class Reader : public Archive<Derived> { 
public: 
    virtual ~Reader() = 0 {} 

    template<typename T> 
    void read(const T& t) { 
    Derived* derived = static_cast<Derived*>(this); 
    derived->read_derived(t); 
    } 
}; 

派生類:

class BinaryWriter : public Writer<BinaryWriter> { 
public: 
    template<typename T> 
    BinaryWriter& serialize_derived(T t) { 
    save(t); 
    return *this; 
    } 

    template<typename T> 
    void save(T t) { 
    std::cout << "DerivedWriter::save: " << t << std::endl; 
    } 

    template<typename T> 
    void write_derived(const T& t) { 
    std::cout << "DerivedWriter::write_derived: " << t << std::endl; 
    } 
}; 

class BinaryReader : public Reader<BinaryReader> { 
public: 
    template<typename T> 
    BinaryReader& serialize_derived(T t) { 
    load(t); 
    return *this; 
    } 

    template<typename T> 
    void load(T t) { 
    std::cout << "DerivedWriter::load: " << t << std::endl; 
    } 

    template<typename T> 
    void read_derived(const T& t) { 
    std::cout << "DerivedReader::read_derived: " << t << std::endl; 
    } 
}; 

示例性測試函數和調用(注:呼叫到寫入器/讀取接口都需要在同樣(派生的其他作家/閱讀器類在這裏省略(即TextReader,XMLReader等))):

template<typename Derived, typename T> 
void do_serialize(Archive<Derived>& obj, T t) { 
    obj.serialize(t); 
} 

DerivedWriter dw; 
DerivedReader dr; 

do_serialize(dw, 1); 
do_serialize(dr, 2); 

輸出:

DerivedWriter::save: 1 
DerivedReader::read: 2 
+0

你想解決什麼問題? – 2012-07-26 22:02:42

+1

爲什麼'test'不是'Derived&obj'並直接調用正確的方法? (因爲你需要在編譯時知道派生類型,無論如何也不能真正使它成爲一個虛函數。) – aschepler 2012-07-26 22:04:44

+0

你在做什麼叫做'CRTP'(或靜態多態),並且很常見。真正的問題在哪裏?模板不需要接口,因爲它們在編譯時被檢查(不考慮'Concepts')。 – pmr 2012-07-26 22:11:00

回答

2

知道這種技術後,被稱爲CRTP(感謝PMR)我發現這個職位CRTP to avoid virtual member function overhead我認爲回答我的問題。正如Kerrek SB在答覆中所說的那樣,這個技術可以用來提供一個接口。在我的情況下,甚至可以爲模板成員函數定義這個接口。

看來這種模式很常見(我不確定),所以我會接受它作爲我的問題的答案。

感謝您的回覆!