I came across a gotcha today with some C++ code I’m working on. I have an abstract base class for doing interpolation, and when I tried converting it to a template class it stopped working – specifically the derived class could no longer access certain members of the base class.
Here’s my abstract base class (simplified for this example):
class Interpolation
{
public:
Interpolation(const string& name, const double& accuracy)
{
_name = name;
_accuracy = accuracy;
_isBuilt = false;
}
virtual void Init(void) = 0;
virtual void LoadFromFile(const string& filename) = 0;
virtual void SaveToFile(const string& filename) = 0;
protected:
string _name;
double _accuracy;
bool _isBuilt;
};
I then have a layer of inheritance on top of that, defining the interface for interpolation in two variables
class Interpolation2D : public Interpolation
{
public:
Interpolation2D(const string& name, const double& accuracy,
const long& Nx, const long& Ny,
const double& xmin, const double& xmax,
const double& ymin, const double& ymax)
: Interpolation (name, accuracy)
{
_grid = new Data2D<double>(Nx, Ny);
...
}
~Interpolation(void)
{
cout << "deleting data grid for " << _name << "\n";
delete _grid;
}
// these are implemented here for two-D interpolations
virtual void SaveToFile(const string& filename);
virtual void LoadFromFile(const string& filename);
protected:
Data2D<double>* _grid;
};
This code was working fine. I have the templated 2D data array class Data2D and chose to use doubles for my interpolation data. The inherited _name and _isBuilt variables work fine, as in the debug output line in the destructor.NB: I do implement the SaveToFile and LoadFromFile functions here, which basically just dump the _grid variable to a binary file.
Then I discovered the rather obvious fact that if I want to make a very fine-grained interpolation, that can take a lot of memory. For example, a 5000×5000 grid of doubles is 5000x5000x8 bytes, i.e. 190MB. Too rich for my laptop at least, although not absurd for most of the machines I use for simulation.
One obvious choice would be to use float instead of double as the data type. Of course, this leads to wanting to template the Interpolation class, which I duly did:
template <class T>
class Interpolation
{
public:
Interpolation(const string& name, const T& accuracy)
{
_name = name;
_isBuilt = false;
_accuracy = accuracy
}
virtual void Init(void) = 0;
virtual void LoadFromFile(const string& filename) = 0;
virtual void SaveToFile(const string& filename) = 0;
protected:
string _name;
bool _isBuilt;
T _accuracy;
};
template <class T>
class Interpolation2D : public Interpolation<T>
{
public:
Interpolation2D(const string& name, const T& accuracy,
const long& Nx, const long& Ny,
const T& xmin, const T& xmax,
const T& ymin, const T& ymax)
: Interpolation<T> (name)
{
_grid = new Data2D<T>(Nx, Ny);
...
}
~Interpolation(void)
{
cout << "deleting data grid for " << _name << "\n";
delete _grid;
}
virtual void SaveToFile(const string& filename);
virtual void LoadFromFile(const string& filename);
protected:
Data2D<T>* _grid;
};
So, imagine my surprise and confusion when this code no longer works. Specifically, gcc complains about the debugging output in the derived class’ destructor.
./include/aon_interpolation.h:179: error: "_name" was not declared in this scope
The problem, according to the C++ FAQ, is that the variable _name is not dependent on the template, and the compile will not look in the base template class to resolve non-dependent names.
Luckily there’s a really easy fix: change the call to use
this->_name
instead: i.e.
cout << data grid for " << this->_name << "\n";
C++ Is just one of those things that constantly surprises me with weird little things like this, even after 7 years of using it. But it’s still so powerful it’s mostly a pleasure to use.