Thanks a lot Romain ! you're amazingly fast and furious (got my seatbelt). I'll definitely buy the book.
That works on my example, I confirm (I had a side problem with using _t which I removed but don't see where this comes from, my side for sure). Now I'm trying to implement it on my "real world" case and I fear that memory management with this solution might poses a small problems. Continuing with our example assume the children class has a field "value_" of type double class children1 : public father { public: double value_ ~children1(){}; children1(){}; children1(double value) : value_(value){}; children1(children1 const & x){}; virtual void WhoAmI() const{ Rcout<<"son1"<<endl; }; }; and one want to create a constructor (in the class vector_Of_father) for a huge vector of children with a NumericVector as input (one value of the vector for one children in the vector) this will require a loop in c++ and my first try could have been vector_Of_father(Rcpp::NumericVector vec) : MyfatherList_(vec.size()) { Rcpp::NumericVector::iterator MyNumericVector_iterator=vec.begin(); int i=0; while ( MyNumericVector_iterator!=vec.end()) { children1 *tmp=Calloc(1,children1); // tmp->value_=*MyNumericVector_iterator; MyfatherList_[i]=tmp; ++MyNumericVector_iterator; i++; } }; and I would felt guilty not doing that: ~vector_Of_father() { std::vector<father*>::iterator it=MyfatherList_.begin(); while (it!=MyfatherList_.end()){ Free(*it); ++it; } }; but that would clearly be against the spirit of Rcpp, I know, and for sure I would not dare to do that (OK, I admit, I tryed and this gave me a leak, (all I deserve ?) ) is there a possibility to convert this into something less intrusive in term of memory allocation ? I know that's not a big problem since I can do the (big) loop in R... but loops in R are like uses of Calloc with Rcpp no ? they are possible but if we can avoid them ... ----- Mail original ----- De: "Romain Francois" <rom...@r-enthusiasts.com> À: rcpp-devel@lists.r-forge.r-project.org Cc: "Robin Girard" <robin.gir...@mines-paristech.fr> Envoyé: Mercredi 3 Avril 2013 22:12:48 Objet: Re: [Rcpp-devel] Module with vector of a class with inheritance, how to avoid slicing Hi, Fasten your seatbelts. First, the problem is definitely object slicing. The best resource I know about to explain it is a chapter of Scott Meyers "Effective C++". Robin, I would highly recommend that you get it. Specially considering that you are willing to get your hands dirty. Anyway, I would suggest that your MyfatherList_ is a vector of father pointers: std::vector<father*> MyfatherList_; if you use any kind of object, even smart pointers, you'll get slicing. Then, you need to have a virtual destructor on the father class and make the WhoAmI methods virtual. This is how you do inheritance in C++. class father { public: virtual ~father(){}; father(){}; father(father const & x) {}; virtual void WhoAmI() const{ Rcout<<"father"<<endl; }; }; class children1_t : public father { public: ~children1_t(){}; children1_t(){}; children1_t(children1_t const & x){}; virtual void WhoAmI() const{ Rcout<<"son1"<<endl; }; }; This is very basic C++ inheritance stuff. The vector class looks like this: class vector_Of_father { public: std::vector<father*> MyfatherList_; ~vector_Of_father(){}; vector_Of_father() : MyfatherList_(){}; father* vec_get( int i) { return MyfatherList_.at(i); }; void WhoAmI(int i) const { MyfatherList_[i]->WhoAmI(); }; int size(){ return(MyfatherList_.size()); }; void push_back(object<father> func){ MyfatherList_.push_back(func); }; }; Some comments. - As I said above, you are storing a vector of pointers. - that makes the implementation of WhoAmI, size simple. - for get_vec, you can just return a pointer to a father. We support this. - for push_back, you need to use object<father>, that is just a disguised pointer. just using father* would require declaring how to handle it. We don't support this yet (for some definition of yet). Anyway, you can just see object<T> as T* Now the module code. RCPP_MODULE(mod_example2){ class_<father>( "father" ) .constructor() .method("WhoAmI",&father::WhoAmI) ; class_<children1_t>( "children1_t" ) .derives<father>("father" ) .constructor() ; class_<children2_t>( "children2_t" ) .derives<father>("father" ) .constructor() ; class_<vector_Of_father>( "vector_Of_father") .constructor() .method( "size", &vector_Of_father::size) .method( "WhoAmI",&vector_Of_father::WhoAmI ) .method( "push_back", &vector_Of_father::push_back ) .method("[[",&vector_Of_father::vec_get) ; } That's it. You don't need to redefine WhoAmI for children classes. The .derives makes it for you. And with this: res <- new( vector_Of_father ) res$push_back(new( father )) res$push_back(new( children1_t )) res$push_back(new( children2_t )) res$WhoAmI(2) res$WhoAmI(1) res$WhoAmI(0) res[[2]]$WhoAmI() res[[1]]$WhoAmI() res[[0]]$WhoAmI() I do get: son2 son1 father son2 son1 father Here is the full code of the .cpp file: #include <Rcpp.h> using namespace std; using namespace Rcpp; class father ; class children1_t; class children2_t ; class vector_Of_father; RCPP_EXPOSED_CLASS(father) RCPP_EXPOSED_CLASS(children1_t) RCPP_EXPOSED_CLASS(children2_t) RCPP_EXPOSED_CLASS(vector_Of_father) class father { public: virtual ~father(){}; father(){}; father(father const & x) {}; virtual void WhoAmI() const{ Rcout<<"father"<<endl; }; }; class children1_t : public father { public: ~children1_t(){}; children1_t(){}; children1_t(children1_t const & x){}; virtual void WhoAmI() const{ Rcout<<"son1"<<endl; }; }; class children2_t : public father { public: ~children2_t(){}; children2_t(){}; children2_t(children2_t const & x){}; virtual void WhoAmI() const{ Rcout<<"son2"<<endl; }; }; class vector_Of_father { public: std::vector<father*> MyfatherList_; ~vector_Of_father(){}; vector_Of_father() : MyfatherList_(){}; father* vec_get( int i) { return MyfatherList_.at(i); }; void WhoAmI(int i) const { MyfatherList_[i]->WhoAmI(); }; int size(){ return(MyfatherList_.size()); }; void push_back(object<father> func){ MyfatherList_.push_back(func); }; }; RCPP_MODULE(mod_example2){ class_<father>( "father" ) .constructor() .method("WhoAmI",&father::WhoAmI) ; class_<children1_t>( "children1_t" ) .derives<father>("father" ) .constructor() ; class_<children2_t>( "children2_t" ) .derives<father>("father" ) .constructor() ; class_<vector_Of_father>( "vector_Of_father") .constructor() .method( "size", &vector_Of_father::size) .method( "WhoAmI",&vector_Of_father::WhoAmI ) .method( "push_back", &vector_Of_father::push_back ) .method("[[",&vector_Of_father::vec_get) ; } Romain Le 03/04/13 18:43, Robin Girard a écrit : > I am still working on my vector of a class father with inheritance > (polymorphic subclasses ?). I created an exemple below that works fine but I > face the known problem of "slicing" as named here : > http://stackoverflow.com/questions/10154977/c-vector-with-inheritance and > fail to implement the proposed solution. > > I have 2 tried 2 things and ended up with 2 questions: > > Question 1 - I tryed the solution proposed in the link with make_shared and > shared_ptr. I had to add PKG_CXXFLAGS=-g -std=c++0x since my MinGW compiler > did not find any -std=c++11. I got no compilation error but when I run the > code it slices my children class : > >> res=new("Rcpp_vector_Of_father") >> res$push_back(new("Rcpp_father")) >> res$push_back_children1_t(new("Rcpp_children1_t")) >> res$WhoAmI(1) > father >> res$WhoAmI(0) > father >> >> res[[1]]$WhoAmI() > father >> res[[0]]$WhoAmI() > father > > > Question 2 - I tryed a solution with XPtr (although I'm not sure how this > works) and got the following error at the module compilation > example_mod_consumption.cpp: In member function 'void > vector_Of_father::push_back_children1_t(children1_t)': > example_mod_consumption.cpp:80:53: error: no matching function for call to > 'std::vector<Rcpp::XPtr<father> >::push_back(Rcpp::XPtr<children1_t>)' XPtr<father> has no relationship with XPtr<children1_t>. They are independant classes generated by the XPtr template class. They don't know about the inheritance. > below are the code for the two approach and at the end the code of the module. > > > > -------------------- Solution with XPtr > > #include <Rcpp.h> > > using namespace std; > using namespace Rcpp; > > class father ; > class children1_t; > class children2_t ; > class vector_Of_father; > > RCPP_EXPOSED_CLASS(father) > RCPP_EXPOSED_CLASS(children1_t) > RCPP_EXPOSED_CLASS(children2_t) > RCPP_EXPOSED_CLASS(vector_Of_father) > > class father > { > public: > ~father(){}; > father(){}; > father(father const & x) {}; > void WhoAmI() const{ > Rcout<<"father"<<endl; > }; > }; > > class children1_t : public father > { > > public: > ~children1_t(){}; > children1_t(){}; > children1_t(children1_t const & x){}; > void WhoAmI() const{ > Rcout<<"son1"<<endl; > }; > }; > > class children2_t : public father > { > public: > ~children2_t(){}; > children2_t(){}; > children2_t(children2_t const & x){}; > void WhoAmI() const{ > Rcout<<"son2"<<endl; > }; > }; > > > class vector_Of_father { > > public: > std::vector<XPtr<father> > MyfatherList_; > //std::vector<shared_ptr<father> > MyfatherList_; > ~vector_Of_father(){}; > vector_Of_father() : MyfatherList_(){}; > father vec_get( int i) { return(*(MyfatherList_.at(i))); }; > > void WhoAmI(int i) const > { > MyfatherList_[i]->WhoAmI(); > }; > int size(){ return(MyfatherList_.size()); }; > > void push_back(father func){ > MyfatherList_.push_back(XPtr<father>(&func)); > }; > > void push_back_children1_t(children1_t func){ > MyfatherList_.push_back(XPtr<children1_t>(&func)); > }; > }; > > -------------------- Solution with make_shared and shared_ptr > > only the class vector_of_father is different also #include <memory> is added > after Rcpp.h include. > > class vector_Of_father { > > public: > std::vector<shared_ptr<father> > MyfatherList_; > ~vector_Of_father(){}; > vector_Of_father() : MyfatherList_(){}; > > father vec_get( int i) { return(*(MyfatherList_.at(i))); }; > > void WhoAmI(int i) const > { > MyfatherList_[i]->WhoAmI(); > }; > int size(){ return(MyfatherList_.size()); }; > > > void push_back(father func){ > MyfatherList_.push_back(make_shared<father>(func)); > }; > void push_back_children1_t(children1_t func){ > MyfatherList_.push_back(make_shared<children1_t>(func)); > }; > }; > > > > -------------- the module code > > RCPP_MODULE(mod_example2){ > using namespace Rcpp; > > class_<father>( "father" ) > //constructors > .constructor() > .method("WhoAmI",&father::WhoAmI) > ; > > class_<children1_t>( "children1_t" ) > .derives<father>("father" ) > //constructors > .constructor() > .method("WhoAmI",&children1_t::WhoAmI) > ; > > class_<children2_t>( "children2_t" ) > .derives<father>("father" ) > //constructors > .constructor() > .method("WhoAmI",&children2_t::WhoAmI) > ; > > class_<vector_Of_father>( "vector_Of_father") > .constructor() > // .constructor<int>() > .method( "size", &vector_Of_father::size) > // .method("capacity", &cplfunctionvec::capacity,"Return size of allocated > storage capacity. Returns the size of the storage space currently allocated > for the vector, expressed in terms of elements.") > // .method( "max_size", &cplfunctionvec::max_size) > .method( "WhoAmI",&vector_Of_father::WhoAmI ) > //.method( "test",&vector_Of_father::test ) > .method( "push_back", &vector_Of_father::push_back ) > .method("push_back_children1_t",&vector_Of_father::push_back_children1_t) > // .const_method( "at", &cplfunctionvec::at ) > .method("[[",&vector_Of_father::vec_get) > // .method("[[<-",&vector_Of_father::vec_set) > ; > > } > > > Dr. Girard Robin > Chargé de Recherche > > MINES-ParisTech / Département Energétique et Procédés / PERSEE / Groupe ERSEI > Centre Procédés, Energies Renouvelables et Systèmes Energétiques (PERSEE) > Center for Processes, Renewables Energies and Energy Systems > Renewable Energies & Smartgrids (ERSEI) > > 1 Rue Claude Daunesse - CS 10207 - F-06904 Sophia Antipolis Cedex > Tel: +33.4.93.67.89.64 (~99), Fax: +33.4.93.95.75.35 > e-mail : robin.gir...@mines-paristech.fr > > web page perso http://www.mines-paristech.fr/Services/Annuaire/&?id=8828 > statoverflow : http://stats.stackexchange.com/users/223/robin-girard > web page centre PERSEE : http://www.cep.mines-paristech.fr/ > linkedin : http://www.linkedin.com/profile/view?id=14907272&trk=tab_pro -- Romain Francois Professional R Enthusiast +33(0) 6 28 91 30 30 R Graph Gallery: http://gallery.r-enthusiasts.com blog: http://blog.r-enthusiasts.com |- http://bit.ly/ZTFLDo : Simpler R help tooltips `- http://bit.ly/YFsziW : R Help tooltips _______________________________________________ Rcpp-devel mailing list Rcpp-devel@lists.r-forge.r-project.org https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel