Ivan Bogush
Ivan Bogush

Reputation: 83

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..

Upvotes: 3

Views: 292

Answers (1)

Marco A.
Marco A.

Reputation: 43662

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)

Upvotes: 4

Related Questions