C ++模板:从基类调用派生模板类的成员函数

时间:2016-03-02 12:50:53

标签: c++ templates inheritance polymorphism

我目前正在处理电子表格应用程序,但我遇到了模板问题。 模板的每个单元格都可以包含一个变量,该变量可以是任何标准类型。

相关的类是SpreadSheet,其最重要的成员变量是SheetCells,具有 输入vector< vector<CellBase*> >CellBase类是CellField<T>所属的抽象类 派生的,后者是存储对应于恰好一个单元的一个数据的模板类 电子表格。

我有另一个类SheetView,最终必须显示电子表格。 (为了简单起见, 假设这个类可以完全访问其他所有类。)这个类并不关心什么类型 每个单元格的值都是,因为它会将所有内容转换为字符串。但是,我的问题是写作 SpreadSheet的成员函数,返回包含数据的字符串。我的第一个想法是编写一个函数 std::string SpreadSheet::getDataFromSheet(int row, int column)会调用SheetView,然后该函数会执行 return (std::to_string(SheetCells[row][column] -> getData())),其中getData()CellField<T>的成员函数,撤退 T类型的东西。 但是,由于SheetCells包含指向CellBase类的指针,因此我必须使getData成为CellBase的成员, 但这是不可能的,因为我希望getData()返回类型为T的变量,与模板类的类型相同 CellField

所有课程定义的相关部分见下文。

//SpreadSheet

class Spreadsheet
{

private:
    int _height, _width;

public:
    Spreadsheet(int newHeight, int newWidth);
    ~Spreadsheet();
    string getData(int row, int column);
    vector< vector<CellBase*> > SheetCells;

};



//CellBase

class CellBase
{
    public:
        CellBase();
        virtual ~CellBase();
};



//CellField

template<typename T>
class CellField : public CellBase
{
    public:
        CellField(T newValue);
        virtual ~CellField();
        T getData();
        T _value;
};

简而言之,我希望能够从getData()调用SpreadSheet,但后者的成员变量 仅包含指向CellBase类的指针(但类实际上是CellField<T>类型)。

我已经查看了类似的问题,但是它们似乎都没有解决调用模板class<T>函数的基类成员函数的问题,后者和前者需要返回类型的变量T。也许void*指针会起作用吗?

2 个答案:

答案 0 :(得分:2)

由于C ++是一种强类型语言,你无法通过这种方式直接调用它们,因为编译器无法弄清楚函数的返回值是什么。

您需要做的是将所有内容映射到一个通用界面。你应该问的问题是:我真正需要从CelField得到什么信息?也许您需要的只是值的字符串表示,然后您可以执行以下操作:

class CellBase
{
    virtual std::string getData()=0;
};

template<typename T>
class CellField : public CellBase
{
    std::string getData(){//some implementation}
};

另一种选择是使用boost::any,它可以包含您喜欢的任何类型。如果您不需要实际干扰返回值,除了将其传递给其他任何参数&#34;任意参数&#34;之外,这一点尤其有用。但是,为了真正使用该值,您仍然必须使用boost::any_cast<T>()将其强制转换为特定类型,因此需要知道您期望的类型,并在类型错误时进行正确的错误处理。

答案 1 :(得分:0)

可能的解决方案是按照以下方式聘请访问者:

Class Visitor
{
   virtual ~Visitor(void) {}
   virtual void visit(CellBase<int> *cell) {}
   virtual void visit(CellBase<float> *cell) {}
...
} ;

class CellBase
{
public:
     CellBase();
     virtual ~CellBase();
     virtual void accept(Visitor *v) { v->visit(this) ;}
};

class DataGetterVisitor : public Visitor
{
public:
    virtual void visit(CellBase<int> *cell) 
    {
       // here I know how to make the transformation

    }
    virtual void visit(CellBase<float> *cell) {}
    string text ;
} ;

string dataGetter(CellBase *cell)
{
    DataGetterVisitor visitor ;
    cell->accept(visitor);
    return visitor.text ;
}