Constructors¶
In the Tutorial we touched upon how to wrap C++ constructors. Now let’s go into more depth.
C++ supports several types of constructors, including:
Default constructors
Copy constructors
Move constructors
Custom constructors
In addition, unlike a Ruby class, a C++ class may include many constructors.
Example¶
For example, consider this simplified version of OpenCV’s Mat class:
class Mat
{
public:
Mat();
Mat(int rows, int cols, int type);
Mat(const std::vector<int>& sizes, int type);
Mat(const Mat& m);
Mat(Mat&& m);
}
The Rice binding for the above example is:
#include <rice/rice.hpp>
#include <rice/stl.hpp>
using namespace Rice;
extern "C"
void Init_Mat()
{
Data_Type<Test> rb_cMat = define_class<Mat>("Mat")
.define_constructor(Constructor<Mat>())
.define_constructor(Constructor<Mat, int, int, int>())
.define_constructor(Constructor<Mat, const std::vector<int>&, int>())
.define_constructor(Constructor<const Mat&>())
.define_constructor(Constructor<Mat&&>());
}
Notice that the Constructor template requires the full list of argument types needed by the constructor.
For more information on how Rice decides which constructor to call, please see the overloaded methods section.
Default Constructor¶
Most C++ classes include a default constructor that takes no arguments. These are mapped to Rice like this:
define_constructor(Constructor<Mat>())
This defines a constructor that takes no arguments. It can be invoked from Ruby using the following code:
Mat.new
Under the hood, the define_constructor
call creates a new initialize
method on the Ruby Mat
class. The initialize
method is responsible for creating a new C++ Mat
instance and associating it with the wrapper Ruby object. Thus if you override the initialize
method you MUST call super
:
class Mat
def initialize
super # <--- You MUST call super first
...your code..
end
end
Custom Constructors¶
The Mat
class defines two custom constructors:
define_constructor(Constructor<Mat, int, int, int>())
define_constructor(Constructor<Mat, const std::vector<int>&, int>())
These are invoked from Ruby like this:
Mat.new(1, 2, 3)
vec = Std::Vector<int>.new
Mat.new(vec, 4)
Similarly to default constructors, calling define_constructor
will creates a new initialize
method on the corresponding Ruby class.
Copy Constructors¶
Most C++ classes include a copy constructor that takes one argument. These are mapped to Rice like this:
define_constructor(Constructor<const Mat&>())
Rice maps copy constructors to Ruby’s clone
and dup
methods:
mat1 = Mat.new(1, 2, 3)
mat2 = mat1.dup
mat3 = mat1.clone
Under the hood, the define_constructor
call creates a new initialize_copy
method on the Ruby Mat class. The initialize_copy
method is responsible for calling the C++ copy constructor and assigning the new C++ instance to the wrapper Ruby object. Thus if you override the initialize_copy
method you MUST call super
:
class Mat
def initialize_copy
super # <--- You MUST call super first
...your code..
end
end
Move Constructors¶
Rice does not currently support move constructors. Of course, you can roll your own support as needed.