Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference to superclass

Tags:

c++

I'd like to use a visitor pattern in combination with smart pointers, but it seems that the compiler can't detect the subclass and match the appropriate function.

I've written an SSCE showing the problem:

test.hpp:

class Visitor;
class Area {
public:
    virtual void visit(const Visitor& visitor) = 0;
};

class Area1 : public Area {
public:
    virtual void visit(const Visitor& visitor);
};

class Area2 : public Area {
public:
    virtual void visit(const Visitor& visitor);
};

class Visitor {
public:
  virtual void visit(const Area1 &area) const = 0;
  virtual void visit(const Area2 &area) const = 0;
};

test.cpp:

#include "test.hpp"

void Area1::visit(const Visitor& visitor) {
    visitor.visit(*this);
}

void Area2::visit(const Visitor& visitor) {
    visitor.visit(*this);
}

main.cpp

#include <iostream>
#include "boost/shared_ptr.hpp"
#include "test.hpp"

class FooVisitor : public Visitor {
    virtual void visit(const Area1 &area) const {
        std::cout <<"visit area1" <<std::endl;
    };
    virtual void visit(const Area2 &area) const {
        std::cout <<"visit area2" <<std::endl;
    }
};

int main(int argc, char** argv) {
    boost::shared_ptr<Area> p(new Area2);
    FooVisitor visitor;
    visitor.visit(*p);
    return 0;
}

The line visitor.visit(*p) gives this error:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:17:21: error: no matching function for call to ‘FooVisitor::visit(Area&)’
main.cpp:17:21: note: candidates are:
main.cpp:6:18: note: virtual void FooVisitor::visit(const Area1&) const
main.cpp:6:18: note:   no known conversion for argument 1 from ‘Area’ to ‘const Area1&’
main.cpp:9:18: note: virtual void FooVisitor::visit(const Area2&) const
main.cpp:9:18: note:   no known conversion for argument 1 from ‘Area’ to ‘const Area2&’

How do I help the compiler realize that visit(const Area2&) should be called without resorting to attempting dynamic_cast to each of the subtypes?

like image 692
dutt Avatar asked Mar 20 '23 09:03

dutt


1 Answers

This can't work, as the type of *p is indeed Area& (based on the type of the pointer). However, you're using it wrong. To correctly apply the visitor pattern, you should call the visit() defined in Area, to get the correct dispatch:

int main(int argc, char** argv) {
    boost::shared_ptr<Area> p(new Area2);
    FooVisitor visitor;
    p->visit(visitor);
    return 0;
}

That's the purpose of the Area::visit() function in the first place.

like image 189
Angew is no longer proud of SO Avatar answered Mar 31 '23 14:03

Angew is no longer proud of SO