Reputation: 5779
I read this blog post about classes and modules in Rcpp and I tried to recreate it, but I am having trouble.
Here is an abbreviated version of the code from the post:
#include <Rcpp.h>
using namespace Rcpp;
class Point {
public:
Point( double x_, double y_) : x(x_), y(y_){}
double x, y ;
} ;
class Shape {
public:
Shape( const Point& center_ ) : center(center_){}
Point center ;
virtual double area() const { return 0.0 ;}
virtual bool contains(const Point& point) const { return false ; }
} ;
RCPP_MODULE(play){
class_<Point>("Point")
.constructor<double,double>()
.field( "x", &Point::x)
.field( "y", &Point::y)
;
class_<Shape>( "Shape" )
.constructor<Point>()
.method( "area", &Shape::area )
.method( "contains", &Shape::contains )
;
};
All that is happening here is the Point class is created, and then used as a parameter in the constructor of the Shape class. But the Shape class won't accept the Point class as a parameter in the constructor. When I compile the above code I get the error: no matching function for call to "Point::Point(SEXPREC*&)". I believe this error is saying that the constructor for Shape doesn't understand how to handle the Point class.
I have read the chapter in the Springer Rcpp
textbook about modules, and I read the vignette about modules, but I don't believe any of them have examples where classes are constructed from other classes like in the above blog post. I must be misunderstanding something so I would appreciate if someone could enlighten me.
Regards
Upvotes: 4
Views: 391
Reputation: 18602
I'm not sure exactly why the code in that blog post was (presumably) valid when it was written and is no longer compiling, but that was roughly three years ago, and some changes to the Modules component of Rcpp have taken place since then. To get this to compile, you can add the following before your class definitions:
class Point; // fwd declarations
class Shape;
class Circle;
class Rectangle;
RCPP_EXPOSED_CLASS(Point);
RCPP_EXPOSED_CLASS(Shape);
RCPP_EXPOSED_CLASS(Circle);
RCPP_EXPOSED_CLASS(Rectangle);
I took the complete code from Romain's C++ example (see below, with a couple of minor modifications) just for the convenience of being able to run the R code also contained in the blog post:
origin <- new( Point, 0, 0 )
pie <- new( Circle, origin, 3 )
##
R> pie$area()
#[1] 28.27433
R> pie$contains( new( Point, 1, 2 ) )
#[1] TRUE
##
rec <- new( Rectangle, origin, 2, 3 )
R> rec$area()
#[1] 6
R> rec$contains( new( Point, 1, 2 ) )
#[1] FALSE
Full code (your compiler will complain without a virtual
destructor in Shape
):
#include <Rcpp.h>
class Point; // fwd declarations
class Shape;
class Circle;
class Rectangle;
RCPP_EXPOSED_CLASS(Point);
RCPP_EXPOSED_CLASS(Shape);
RCPP_EXPOSED_CLASS(Circle);
RCPP_EXPOSED_CLASS(Rectangle);
class Point {
public:
Point( double x_, double y_) : x(x_), y(y_){}
double x, y ;
} ;
double square( double x) {
return x*x ;
}
double distance( const Point& p1, const Point& p2 ){
return sqrt( square( p1.x - p2.x) + square( p1.y - p2.y ) ) ;
}
class Shape {
public:
Shape( const Point& center_ ) : center(center_){}
virtual ~Shape() {}
Point center ;
virtual double area() const { return 0.0 ;}
virtual bool contains(const Point& point) const { return false ; }
} ;
class Circle : public Shape {
public:
Circle( Point center_, double radius_ ): Shape(center_), radius(radius_){}
double area() const {
return PI * square( radius ) ;
}
bool contains( const Point& point ) const {
return distance(point, center) < radius ;
}
double radius ;
} ;
class Rectangle : public Shape {
public:
Rectangle( Point center_, double width_, double height_ ) :
Shape(center_), width(width_), height(height_){}
double area() const {
return width * height ;
}
bool contains( const Point& point ){
return (point.x >= ( center.x - width / 2.0 )) &&
(point.x <= ( center.x + width / 2.0 )) &&
(point.y >= ( center.y - height / 2.0 )) &&
(point.y <= ( center.y + height / 2.0 ));
}
double width, height ;
} ;
RCPP_MODULE(play){
using namespace Rcpp;
class_<Point>("Point")
.constructor<double,double>()
.field( "x", &Point::x)
.field( "y", &Point::y)
;
class_<Shape>( "Shape" )
.constructor<Point>()
.method( "area", &Shape::area )
.method( "contains", &Shape::contains )
;
class_<Circle>( "Circle" )
.derives<Shape>("Shape" )
.constructor<Point,double>()
.field( "r", &Circle::radius )
;
class_<Rectangle>( "Rectangle" )
.derives<Shape>("Shape" )
.constructor<Point,double,double>()
.field( "h", &Rectangle::height )
.field( "w", &Rectangle::width )
;
};
Upvotes: 5