2011-07-02 35 views
2

我知道這不是合法的C++,因爲編譯器無法確定vtable究竟有多大。我正在尋找替代品。如何繞過模板虛擬功能來實現我的目標?

基本上,我有一個抽象基類定義了一組派生類的接口。通過此接口公開的某些函數的返回值由輸入參數sKeyName確定。我的預期代碼發佈在下面。

class DataAccess 
{ 
    public: 
     template <class T> 
     virtual const Array2D<T>* GetData(std::string sKeyName) const = 0; 

     template <class T> 
     virtual Array2D<T>* GetData(std::string sKeyName) = 0; 
}; 

有人可以給我一個解決方法來獲得此功能嗎?任何幫助表示讚賞。先謝謝你。

+1

接縫你打破了「告訴別人不要」的設計原則。你究竟想要歸檔什麼? –

回答

0

讓所有您可以從GetData返回的不同類型從基類繼承並返回指向該類的指針。例如:

class Data {}; 
class Array2D: public Data{}; 
class DataAccess 
{ 
    public: 
     virtual Data* GetData(std::string sKeyName) const = 0; 
}; 
0

我不確定這是否回答您的問題,但您可以查看CRTP。那麼你會這樣做:

template< typename T > 
struct B 
{ 
    virtual Array2D<T>* GetData(std::string sKeyName) = 0; 
}; 

struct A : public B<int> 
{ 
    virtual Array2D<int>* GetData(std::string sKeyName) 
    { 
    // implement 
    } 
}; 
4

你需要做的是定義一個單獨的,模板化的接口。

class DataAccess { 
    template<typename T> class InnerInteface { 
     virtual Array2d<T>* GetData(std::string) = 0; 
    }; 
}; 
class OHai : public DataAccess, DataAccess::InnerInterface<float> { 
}; 
int main() { 
    DataAccess* D = new OHai; 
    if (DataAccess::InnerInterface<float>* data = 
     dynamic_cast<DataAccess::InnerInterface<float>>(D)) { 
    } 
} 

可能得到你所需要的。你也可以模擬基類,但我猜這是不允許的。

+0

爲什麼從DataAccess繼承?看起來像一個空的類;) –

+0

@VJo:因爲這給所有的數據訪問器一個共同的基類。只從模板繼承,沒有公共基類。 –

+1

您需要使'DataAccess'多態(例如通過賦予它一個虛擬析構函數)使'dynamic_cast'工作。 –

0
  • 模板函數不能是虛擬的。
  • Array2D需要一個模板參數。即使模板類的類型是默認值,也需要<>
3

你問有關動態功能,但你的主要問題是不存在的,而是在這裏:

的一些通過這個接口暴露的函數的返回值是通過輸入參數確定sKeyName。

C++是一種靜態類型語言,這意味着您不能有一個依賴於參數值的函數的返回類型。忽略暫時繼承,你提供的代碼需要用戶確定正在返回獨立的傳遞的參數陣列的類型:現在

struct SimpleDataAccess { 
    template <typename T> 
    array2d<T>* get_data(std::string const & which) { 
     return new array2d<T>(); 
    } 
}; 
int main() { 
    SimpleDataAccess accessor; 
    array2d<int> = accessor.get<int>("int"); // <int> at the place of call fixes 
               // the return type, not "int" ! 
} 

,如果你願意忍受(即調用者會知道並設置返回類型),有不同的方式爲您的特定語言問題提供解決方法,但不允許使用模板化的虛擬功能。首先想到的是,它也遵循NVI慣用法(並顯示其重要性):爲數據提供一個非虛擬公共模板訪問器,並根據固定返回類型的虛函數實現它。

class DataAccessor { 
    virtual Type get_data_impl(std::string const &) = 0; 
public: 
    template <typename T> 
    array2d<T>* get_data(std::string const & which) { 
     Type tmp = get_data_impl(which); 
     return convert(tmp); 
    } 
}; 

假設我們能解決什麼Typeconvert是,我們有一個解決方案。這是NVI慣用語的一個很好的例子:用戶提供的接口(公共,非虛擬)與擴展(私有,虛擬)所需的接口不同。這兩個合同有所不同,您的用戶需要您提供指向特定具體array2d實例化的指針,但該語言不允許您從擴展需要相同的合同,但這不是問題,因爲它們是不同的接口。

現在回到Typeconvert。這兩個是相關的,你可以遵循不同的方法。最簡單的實現將具有array2d_base類,所有array2d<T>派生(通過提供一個虛擬的析構函數啓用RTTI):

struct array2d_base { 
    virtual ~array2d_base() {} 
}; 
template <typename T> 
class array2d : public array2d_base { 
    // implementation 
}; 
// Type == array2d_base* 
// convert == dynamic_cast< array2d<T>* > 
template <typename T> 
array2d<T>* DataAccessor::get_data(std::string const & s) { 
    return dynamic_cast< array2d<T>* >(get_data_impl(s)); 
} 

如果您不能擴展或修改array2d類,那麼你也可以達到類似的結果通過類型擦除。這將具有在array2d中不要求RTTI的優點,但僅在類型擦除支持中。最簡單的實現方式是在內部接口中使用boost::any

// Type == boost::any 
// convert == boost::any_cast< array2d<T>* > 
template <typename T> 
array2d<T>* DataAccessor::get_data(std::string const & s) { 
    boost::any tmp = get_data_impl(s); 
    return boost::any_cast< array2d<T>* >(tmp); 
} 
+0

當我發佈我的問題後,沉澱的迫切性迫使我離開我的電腦。對所有回答我的問題的人抱歉。 – GoldenLee