你問有關動態功能,但你的主要問題是不存在的,而是在這裏:
的一些通過這個接口暴露的函數的返回值是通過輸入參數確定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);
}
};
假設我們能解決什麼Type
和convert
是,我們有一個解決方案。這是NVI慣用語的一個很好的例子:用戶提供的接口(公共,非虛擬)與擴展(私有,虛擬)所需的接口不同。這兩個合同有所不同,您的用戶需要您提供指向特定具體array2d
實例化的指針,但該語言不允許您從擴展需要相同的合同,但這不是問題,因爲它們是不同的接口。
現在回到Type
和convert
。這兩個是相關的,你可以遵循不同的方法。最簡單的實現將具有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);
}
接縫你打破了「告訴別人不要」的設計原則。你究竟想要歸檔什麼? –