我知道这不是合法的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;
};
有人可以给我一个解决方法来获得此功能吗?任何帮助表示赞赏。提前谢谢。
答案 0 :(得分: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)) {
}
}
这个可能可以满足您的需求。你也可以模拟基类,但我猜这是不允许的。
答案 1 :(得分: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习惯用法(并显示其重要性):为数据提供非虚拟公共模板化访问器,并根据固定返回类型虚函数实现它。 / p>
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 );
}
答案 2 :(得分:0)
让所有可以从GetData返回的不同类型继承自基类并返回指向该类的指针。例如:
class Data {};
class Array2D: public Data{};
class DataAccess
{
public:
virtual Data* GetData(std::string sKeyName) const = 0;
};
答案 3 :(得分: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 :(得分:0)
Array2D
需要模板参数。即使模板类的类型是默认类型,也需要<>
。