Ivan Bogush Ivan Bogush - 11 days ago 8
C++ Question

Error "Pure virtual function called" in template derived class

I need to make a general

Robot
which would find path on a general
Surface
.

So here is my
Surface
interface:

template <typename P>
class Surface {
public:
virtual int distance(const P& from, const P& to) const = 0;
virtual bool check(const vector<P>& path, const P& from, const P& to) const = 0;
virtual vector<P> lookAround(const P& at) const = 0;
};


Here I create a simple
PlanarSurface
:

class PlanarSurface : public Surface<pair<int, int>> {
public:
using point_type = pair<int, int>;
int distance(const point_type& from, const point_type& to) const override {
return to.first - from.first + to.second - from.second;
}

bool check(const vector<point_type>& path,
const point_type& from,
const point_type& to) const override {
return true; // there would be the check
}

vector<point_type> lookAround(const point_type& at) const override {
vector<point_type> result;
//...
return result;
}
};


Now I create an abstract class
Robot
so that every user-implemented robot would extend it:

template <typename P>
class Robot {
public:
Robot(const Surface<P>& s): surface(s) {}
vector<P> findPath(const P& from, const P& to) {
auto path = searchPath(from, to);
if (surface.check(path, from, to)) {
return path;
}
throw runtime_error("path not found or incorrect");
}
private:
virtual vector<P> searchPath(const P& from, const P& to) = 0;
protected:
const Surface<P>& surface;
};


There
searchPath
private method would be responsible for custom search algorithm, defined in children of
Robot
.
Suppose I have one:

template <typename P>
class MyRobot: public Robot<P> {
public:
MyRobot(Surface<P> m): Robot<P>(m) {}
private:
vector<P> searchPath(const P& from, const P& to) override {
vector<P> result;
// ...
// use one of surface's virtual methods
auto dist = this->surface.distance(from, to); // Pure virtual function called!
cout << dist << endl;
// ...
return result;
}
};


And finally the
main
function:

int main(const int argc, const char **argv) {
PlanarSurface plane;
MyRobot<pair<int, int>> robot(plane);
robot.findPath({1,2}, {3,4});
return 0;
}


So the problem is that as the reference to
surface
is stored in base
Robot
class we can't specify it's type with some derived of
Surface
class. So the type of the reference can only be
Surface<P, M>
.

We need to use
surface
's
distance
and
lookAround
methods in our search algorithm in every child of
Robot
. But in
Surface<P, M>
they are pure virtual. And they can be implemented only in children of
Surface<P, M>
.

Help me please! Maybe I missed something obvious..

Answer

The error is here:

MyRobot(Surface<P> m) : Robot<P>(m) {}
        ^^^^^^^^^^^^ value

change it to accept a reference instead

MyRobot(Surface<P>& m) : Robot<P>(m) {}

Interestingly both MSVC and gcc diagnose this problem along the lines of

invalid abstract parameter

while clang doesn't even emit a warning about this (at the time of writing this post - 4.0)