MMM
MMM

Reputation: 972

How to avoid defining a wrapper for abstract base class if I only expose derived classes to python but still use the base class non virtual methods?

Given this class

class ABC {
  const std::string& getid() const;
  /// other pure virtual methods
};

class D1 : public ABC {
  /// override and implement virtual methods  
};
class D2 : public ABC {
  /// override and implement virtual methods  
};

if I expose D1 and D2 to boost::python like so:

class_<D1, D1*>("D1", "...")
  .def(getid, &ABC::getid)
;

the call from python to a D1 instance getid() triggers this error:

Boost.Python.ArgumentError: Python argument types in
    D1.getid(D1)
did not match C++ signature:
    getid(D1 {lvalue})

Is this to do const-correctness, with the implicit python self?

Upvotes: 0

Views: 78

Answers (1)

Arun Panneerselvam
Arun Panneerselvam

Reputation: 2335

yes, this error is very much related to 'const-correctness'. the problem is your getid method is declared as const std::string& getid() const;. it means not to modify it's state.

two possible solutions, first, overload getid such that boost will select the correct overload to avoid a wrapper.

you can add a non-const overload func for getid

 class ABC {
  public:
  virtual std::string getid() = 0; //pure virtual, return just a '0'
  const std::string& getid() const {
   return 'ABC-id'; }
  /// other pure virtual methods
  virtual ~ABC() = default; //needed for polymorphism with boost::python
}

class D1 : public ABC {
  public:
  /// override and implement virtual methods
  std::string getid() override {  //return the id for D1
   return 'D1';
}

class D2 : public ABC {
  public:
  /// override and implement virtual methods 
 
   std::string getid() override {   
      //return the id for D2. 
      return 'D2'; 
   }
};

imo, overloading the getid function is straight forward than a wrapper class.

UPDATE: expose it like this,

class_<ABC, boost::noncopyable>("ABC");  //now it's baseclass, no copying

class_<D1, boost::python::bases<ABC>, D1*>("D1")
    .def("getid", &ABC::getid) // this will the correct overload now
    ;

same for class D2.

Upvotes: -1

Related Questions