Prev: C++ Passion = Madness
Next: Assignment operator definition required in case of reference data member why?
From: Hicham Mouline on 13 May 2010 04:13 Hello, I have struct params { double field1; double field2; virtual ~params() {} }; struct params1 : public params { double fielda; double fieldb; }; I have dozens of structs derived from params. I work mostly with params& and params* and const versions. Given a const params& p, I wish to clone the object referred to it. If p happens to params32, I wish to obtain a new instance of that object (in that all the fields are copied to the new object, including the fields specific to params32 of course) I could add a non pure virtual function "params* clone() const" but then I'd have to add a clone() to all of the params_i Is there a way to obtain this without touching at all any of the derived structs? regards, -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Andy Venikov on 13 May 2010 08:38 Hicham Mouline wrote: > Hello, > I have > struct params { > double field1; > double field2; > virtual ~params() {} > }; > struct params1 : public params { > double fielda; > double fieldb; > }; > I have dozens of structs derived from params. > I work mostly with params& and params* and const versions. > Given a > const params& p, > I wish to clone the object referred to it. > If p happens to params32, I wish to obtain a new instance of that object (in that all the fields are copied to the new object, including the fields specific to params32 of course) > I could add a non pure virtual function "params* clone() const" but then I'd have to add a clone() to all of the params_i > Is there a way to obtain this without touching at all any of the derived structs? > regards, I'm afraid not. Is your concern that you don't want to define clone() for every derived class? If it's OK for you to change each derived class declaration from struct derivedXXX : public params to struct derivedXXX : public clonable_params<derivedXXX> Then you won't have to define clone() for every class. Just once in the base class. I.e. struct params { protected: virtual params * do_clone() const =0; public: params * clone() const { return do_clone(); } // }; template <typename T> struct clonable_params : public params { T * do_clone() const { return new T(*static_cast<T*>(this)); } }; HTH, Andy. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Juan Pedro Bolivar Puente on 13 May 2010 08:39 On 13/05/10 22:13, Hicham Mouline wrote: > Hello, > > I have > > struct params { > double field1; > double field2; > virtual ~params() {} > }; > > struct params1 : public params { > double fielda; > double fieldb; > }; > > I have dozens of structs derived from params. > > I work mostly with params& and params* and const versions. > Given a > const params& p, > I wish to clone the object referred to it. > > If p happens to params32, I wish to obtain a new instance of that object (in that all the fields are copied to the new object, including the fields specific to params32 of course) > > I could add a non pure virtual function "params* clone() const" but then I'd have to add a clone() to all of the params_i > > Is there a way to obtain this without touching at all any of the derived structs? > There isn't. But you can make a semi-automatic way to solving the problem: template <class T> struct copy_cloneable : public T { virtual copy_cloneable* clone() { return new copy_cloneable (*this); } virtual ~copy_cloneable () {} }; .... And for every params: struct params_N_def : public params_M { ... }; typedef copy_cloneable<params_N_def> params_N; Which are changes that you might even be able to automatize. JP -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Juan Pedro Bolivar Puente on 14 May 2010 00:49 > > If it's OK for you to change each derived class declaration from > > struct derivedXXX : public params > to > struct derivedXXX : public clonable_params<derivedXXX> > > Then you won't have to define clone() for every class. Just once in the > base class. > > I.e. > > struct params > { > protected: > virtual params * do_clone() const =0; > > public: > params * clone() const > { > return do_clone(); > } > // > }; > > template <typename T> > struct clonable_params : public params > { > T * do_clone() const > { > return new T(*static_cast<T*>(this)); > } > }; > > The problem that I see with your solution is that it is limited to one step hierarchies and that the cloning method overriding lacks covariance. There is actually no way to make a solutions based on inheriting from the "auto-clone" class that can respect covariance because in that case the "auto-clone"d type is incomplete in the context of the clone() function definition and therefore the compiler complains about covariance. As an example: template <class T, class Next = void> struct copy_cloneable : public Next { virtual T* clone() { return new T (*static_cast<T*>(this)); } virtual ~copy_cloneable () {} }; template <class T> struct copy_cloneable<T, void> { virtual T* clone() { return new T (*static_cast<T*>(this)); } virtual ~copy_cloneable () {} }; struct A : public copy_cloneable<A> {}; struct B : public copy_cloneable<B, A> {}; Yields: test.cpp: In instantiation of 'copy_cloneable<B, A>': test.cpp:19: instantiated from here test.cpp:7: error: invalid covariant return type for 'T* copy_cloneable<T, Next>::clone() [with T = B, Next = A]' test.cpp:14: error: overriding 'T* copy_cloneable<T, void>::clone() [with T = A]' With GCC. (Yeah, actually I built the code thinking that it was a good solution just to realize about this partial definition problem, it's too late in my time zone :p) JP -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Andy Venikov on 14 May 2010 07:20 Juan Pedro Bolivar Puente wrote: <snip> > There is actually no way to make a solutions based on inheriting from > the "auto-clone" class that can respect covariance because in that case > the "auto-clone"d type is incomplete in the context of the clone() > function definition and therefore the compiler complains about covariance. > As an example: > template <class T, class Next = void> > struct copy_cloneable : public Next > { > virtual T* clone() { return new T (*static_cast<T*>(this)); } > virtual ~copy_cloneable () {} > }; > template <class T> > struct copy_cloneable<T, void> > { > virtual T* clone() { return new T (*static_cast<T*>(this)); } > virtual ~copy_cloneable () {} > }; > struct A : public copy_cloneable<A> {}; > struct B : public copy_cloneable<B, A> {}; > Yields: > test.cpp: In instantiation of 'copy_cloneable<B, A>': > test.cpp:19: instantiated from here > test.cpp:7: error: invalid covariant return type for 'T* > copy_cloneable<T, Next>::clone() [with T = B, Next = A]' > test.cpp:14: error: overriding 'T* copy_cloneable<T, void>::clone() > [with T = A]' > With GCC. > (Yeah, actually I built the code thinking that it was a good solution > just to realize about this partial definition problem, it's too late in > my time zone :p) > JP Huh, interesting point. I didn't compile the code myself that's why I didn't see this issue. You're right, there is no way to do co-variant returns with my solution. They are not strictly needed with my approach though, because I resorted to Non-Virtual Interface idiom and you can't do covariant returns with it anyway. I like your solution, except that in C++03 you'll hit a road bump if the params class has a non-trivial constructor. In my solution I lay the burden of writing all non-trivial constructors on params_XXX classes that can just call the correct non-trivial constructor of params class. In you solution it's just not possible. In C++0x on the other hand, you'll be able to inherit constructors, so your solution will work great there. Andy. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
|
Next
|
Last
Pages: 1 2 Prev: C++ Passion = Madness Next: Assignment operator definition required in case of reference data member why? |