2014-07-17 28 views
0

我有一個類Base,我有兩個類,DerivedADerivedB定義如下。C++中的奇怪循環模板模式(CRTP)的多態集合?

template <typename Derived> 
class Base{ 
public: 
    double interface(){ 
     static_cast<Derived*>(this)->implementation(); 
    } 
}; 

class DerivedA : public Base<DerivedA>{ 
public: 
    double implementation(){ return 2.0;} 
}; 

class DerivedB : public Base<DerivedB>{ 
public: 
    double implementation(){ return 1.0;} 
}; 

總之,我嘗試做以下,以保持對象,其中一些是DerivedA的集合,其中有些是DerivedB

std::vector<std::shared_ptr<Derived>> 

這顯然是不可能怎麼一回事,因爲我現在已經將類Derived作爲模板類。

有什麼辦法可以創建/維護對象的多態集合嗎?

編輯:不幸的是,一個簡單的模板化結構不起作用,因爲函數implementation是模板在我的實際程序 - 所以然後implementation將不得不是一個模板化的純虛函數,這是不可能的。請原諒我缺乏解釋。

+1

** - 1 **所呈現的代碼在語法上無效(例如'Class') –

+1

並且「派生」不是您的僞代碼中的類型 – quantdev

+0

對不起,在我的示例中修復了錯綜複雜的錯別字。當前(更新)的帖子格式正確。有沒有我能做的模板元編程? – druckermanly

回答

5

Alf的建議是有針對性的。很容易使其適應您的額外要求。定義一個接口採用了純虛方法:

struct BaseInterface { 
    virtual ~BaseInterface() {} 
    virtual double interface() = 0; 
}; 

現在,你的模板基類可以從接口派生:

template <typename Derived> 
class Base : BaseInterface { 
public: 
    double interface(){ 
     static_cast<Derived*>(this)->implementation(); 
    } 
}; 

現在,您可以創建指針的向量接口:

std::vector<std::shared_ptr<BaseInterface>> 
+0

哇,儘管我的問題的可怕解釋(我正在重寫我的問題,以至於它至少可以理解......)你給出了我正在尋找的確切答案,非常感謝你! – druckermanly

+0

非常歡迎你把Alf的建議放在心上: – jxh

+0

「Base」正在做什麼?爲什麼'Derived'不能直接從'BaseInterface'繼承? –

6

本答案屬於這個問題,因爲這個答案的時間是


請勿使用不是動態多態性的CRTP來創建動態多態性。

使用虛擬功能。

這就是他們的目的。

class Base 
{ 
private: 
    virtual 
    auto implementation() -> double = 0; 

public: 
    auto interface() -> double { return implementation(); } 
}; 

class DerivedA 
    : public Base 
{ 
private: 
    auto implementation() -> double override { return 2.0; } 
}; 


class DerivedB 
    : public Base 
{ 
private: 
    auto implementation() -> double override { return 1.0; } 
}; 
+0

不幸的是,我需要一個模板化的純虛函數 - 這在C++標準中是不允許的。 – druckermanly

+2

@ user2899162:沒有辦法downvote您的額外要求在一個評論:( –

+0

我知道,我很抱歉,我想比我打字快得多 – druckermanly

0

因爲Base<DerivedA>是一個完全不同的類型相比Base<DerivedB>,你是對的,你不能只是像做std::vector<std::shared_ptr<Base>>,因爲這將是語法無效,有關於C++沒有明確的語義。

實現你想要什麼的一種方法保留你當前的CRTP層次結構是創建一個類型擦除接口(或者它應該被調用?我不確定...)。它基本上是一個包裝器,它定義了一個可以包裝符合該接口的對象的特定接口。

#include <vector> 
#include <memory> 
#include <iostream> 


class VirtualBase { // Really am not sure what it should be called, sorry 
    class Interface { 
    public: 
     virtual ~Interface() = default; 
     virtual double get() = 0; 
    }; 

    template<typename T> 
    class Impl : public Interface { 
     T m_impl_obj; 

    public: 
     Impl(T impl_obj) : m_impl_obj(std::move(impl_obj)) {} 

     double get() override { 
      return m_impl_obj.get(); 
     } 
    }; 

    std::shared_ptr<Interface> m_obj; 

public: 
    template<typename T> 
    VirtualBase(T obj) : m_obj(new Impl<T>(std::move(obj))) {} 

    double get() { 
     return m_obj->get(); 
    } 
}; 


template <typename Derived> 
class Base{ 
public: 
    double get(){ 
     return static_cast<Derived*>(this)->implementation(); 
    } 
}; 

class DerivedA : public Base<DerivedA>{ 
public: 
    double get(){ return 2.0;} 
}; 

class DerivedB : public Base<DerivedB>{ 
public: 
    double get(){ return 1.0;} 
}; 


int main() { 
    std::vector<VirtualBase> v; 
    v.emplace_back(DerivedA{}); 
    v.emplace_back(DerivedB{}); 

    for(auto b : v) { 
     std::cout << b.get() << std::endl; 
    } 
} 

Live example

這是相當不完整的,但它應該工作,至少在我的情況,如果我需要這樣的設計。 Sean Parent在2013年GoingNative上的講話:http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil,是一篇很好的介紹,解釋和理解如何和爲什麼。真的,你應該看到它,包括GoingNative中的所有其他精彩演講。

0

編輯:這是基於OP實際需要虛擬功能模板的假設。這顯然不是這種情況。


這是不可能有虛擬功能模板。

部分模擬它們的一種方式是訪問者模式。它通常用於將動態調度的功能添加到現有的類中。這種附加功能可以被模板化的事實往往被忽視。

僞代碼示例

class Base 
{ 
    virtual void accept (Visitor*) = 0; 
} 

class Derived1 : public Base 
{ 
    void accept(Visitor* v) { v->visit(this); } 
} 

類Derived2的:公共基地 { 空隙接受(訪問者* V){V->訪問(本); }}

class Visitor 
{ 
    virtual void visit (Derived1*) = 0; 
    virtual void visit (Derived2*) = 0; 
} 

template<class X, class Y> 
class FooVisitor 
{ 
    X x; Y y; 
    FooVisitor(X x, Y y): x(x), y(y) {} 

    void visit (Derived1*) { x.func(y); } 
    void visit (Derived2*) { y.otherfunc(x); } 
    } 

當然所有參觀者的缺點是在這裏。