Reputation: 172
I'm currently working on a spreadsheet application, but I'm having problems with templates. Every cell of the template can contain a variable which can be any of the standard types.
The relevant class is SpreadSheet
, whose most important member variable is SheetCells
, which has
type vector< vector<CellBase*> >
. The CellBase
class is an abstract class from which CellField<T>
is
derived, the latter being the template class storing one piece of data corresponding to exactly one cell
of the spreadsheet.
I have another class, SheetView
, that eventually has to display the spreadsheet. (To keep things simple,
assume that this class has full access to every other class.) This class doesn't really care what type
the value of every cell is, as it will convert everything to a string anyway. However, my problem is writing
a member function of SpreadSheet
that returns a string, containing the data. My first idea was to write a function
std::string SpreadSheet::getDataFromSheet(int row, int column)
that SheetView
would call, and then that function would do
return (std::to_string(SheetCells[row][column] -> getData()))
, where getData()
is a member function of CellField<T>
, returing
something of type T
.
However, since SheetCells
contains pointers to CellBase
classes, I must make getData
a member of CellBase
,
but this is not possible, since I want getData()
to return a variable of type T
, the same type as the template class
CellField
.
The relevant parts of all class definitions are found below.
//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;
};
So in short, I want to be able to call getData()
from SpreadSheet
, but the member variables of the latter
only contain pointers to CellBase
classes (but the classes are actually of type CellField<T>
).
I've looked at similar questions, but none of them seem to address the issue of a base class member function calling a template class<T>
function where the latter and the former need to return a variable of type T
. Maybe void*
pointers will work?
Upvotes: 1
Views: 1040
Reputation: 5230
A possible solution is employ a visitor, along these line:
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 ;
}
Upvotes: 0
Reputation: 4275
As C++ is a strongly typed language, you can't call them directly this way, since the compiler would not be able to figure out what the return value of the function is.
What you need to do is, map it all to a common interface. The question you should ask is: what are the information i realy need from the CelField? Maybe all you need is the string-representation of the value, then you could do something like this:
class CellBase
{
virtual std::string getData()=0;
};
template<typename T>
class CellField : public CellBase
{
std::string getData(){//some implementation}
};
Another option is the use of boost::any
, which is able to contain any type you like. This is especially useful if you don't need to actually interfere with the returned value other than passing it to some other function taking "an arbitrary parameter". However in order to really use the value, you still have to cast it to a specific type using boost::any_cast<T>()
and therefore need to know which type you expect and do a proper error-handling if the type is wrong.
Upvotes: 2