如何绕过模板虚拟功能来实现我的目标?

时间:2011-07-02 08:23:32

标签: c++ templates function virtual

我知道这不是合法的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; 
}; 

有人可以给我一个解决方法来获得此功能吗?任何帮助表示赞赏。提前谢谢。

5 个答案:

答案 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 );
    }
};

假设我们可以解决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 );
}

答案 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需要模板参数。即使模板类的类型是默认类型,也需要<>