【问题标题】:C++ templates: Calling member function of derived template class from base classC++模板:从基类调用派生模板类的成员函数
【发布时间】:2016-03-02 12:50:53
【问题描述】:

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

相关类是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;
};

所以简而言之,我希望能够从SpreadSheet调用getData(),但是后者的成员变量 只包含指向CellBase 类的指针(但这些类实际上是CellField&lt;T&gt; 类型)。

我看过类似的问题,但似乎都没有解决基类成员函数调用模板class&lt;T&gt; 函数的问题,后者和前者需要返回T 类型的变量。也许void* 指针会起作用?

【问题讨论】:

  • 许多可能的答案...我将使用虚拟纯函数“getData”,它返回一个 boost::any,它允许您存储许多不同的类型

标签: c++ templates inheritance polymorphism


【解决方案1】:

由于 C++ 是一种强类型语言,因此不能直接这样调用它们,因为编译器无法判断函数的返回值是什么。

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

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

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

另一个选项是使用boost::any,它可以包含您喜欢的任何类型。如果您不需要实际干预返回值,只需将其传递给采用“任意参数”的其他函数,这将特别有用。但是,为了真正使用该值,您仍然必须使用 boost::any_cast&lt;T&gt;() 将其转换为特定类型,因此需要知道您期望的类型,并在类型错误时进行适当的错误处理。

【讨论】:

  • 这正是我所需要的。编译没有错误并产生正确的结果。
  • 我想建议使用override 关键字来防止将来出现问题(例如通过重命名函数)
【解决方案2】:

一个可能的解决方案是雇佣一个访客,按照以下思路:

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 ;
}

【讨论】:

    猜你喜欢
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 2021-07-25
    • 2016-08-17
    • 1970-01-01
    • 2011-05-11
    • 2010-12-22
    相关资源
    最近更新 更多