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.