I'm sure this is a frequently asked question, but...
Suppose that I have a hierarchy of objects which are typically allocated dynamically and handled with some smart pointer or whatever. However, I want to be able to create copies of those objects, while having only a pointer-to-base-class. The solution is to write a clone() member function like this:
class Base { public: virtual Base* clone() const { return new Base(*this); }
// other stuff here
};
The problem is that this clone() function must be replicated in all the derived classes as well, and their implementation is always the same, except for the type which is being allocated. For example:
class Derived: public Base { public: virtual Base* clone() const { return new Derived(*this); }
};
It's not only tedious to have to write this line in each of the derived classes, but it's also error-prone: If you ever forget to add that line to some derived class, no compiler error will happen, and the program will even run, but when cloning a derived object using a base type pointer, you get a crippled copy, so the whole thing malfunctions, and it might malfunction in a very non-obvious way which is hard to track and debug.
Isn't there any way of automating this process? (And without making the base class a template class, which would be rather tedious if the base class is large, especially since we don't have export templates in practice.)
> class Base > { > public: > virtual Base* clone() const { return new Base(*this); }
> // other stuff here
> };
> The problem is that this clone() function must be replicated in all > the derived classes as well, and their implementation is always the > same, except for the type which is being allocated. For example:
> class Derived: public Base > { > public: > virtual Base* clone() const { return new Derived(*this); }
> };
> It's not only tedious to have to write this line in each of the > derived classes, but it's also error-prone: If you ever forget to add > that line to some derived class, no compiler error will happen, and the > program will even run, but when cloning a derived object using a base > type pointer, you get a crippled copy, so the whole thing malfunctions, > and it might malfunction in a very non-obvious way which is hard to > track and debug.
Make the Base::clone() method pure and don't provide a body. this way, if the derived class doesn't implement the clone() method, the linker will complain.
Sana wrote: > On Feb 20, 9:25 am, Juha Nieminen <nos...@thanks.invalid> wrote: >> class Base >> { >> public: >> virtual Base* clone() const { return new Base(*this); }
>> // other stuff here
>> };
>> The problem is that this clone() function must be replicated in all >> the derived classes as well, and their implementation is always the >> same, except for the type which is being allocated. For example:
>> class Derived: public Base >> { >> public: >> virtual Base* clone() const { return new Derived(*this); }
>> };
>> It's not only tedious to have to write this line in each of the >> derived classes, but it's also error-prone: If you ever forget to add >> that line to some derived class, no compiler error will happen, and the >> program will even run, but when cloning a derived object using a base >> type pointer, you get a crippled copy, so the whole thing malfunctions, >> and it might malfunction in a very non-obvious way which is hard to >> track and debug.
> Make the Base::clone() method pure and don't provide a body. this way, > if the derived class doesn't implement the clone() method, the linker > will complain.
Then the problem would be with a derived class of a derived class (a "grandchild" of Base). Once the derived has implemented the clone function, any of its own derived classes won't be forced to do that.
And that's actually reflected in the original inquiry since Base::clone is *not* pure. IOW there is no simple way to force (or provide) the implementation of such a "clone" function in the derived class *in case* the base class' member is not pure.
In certain circles, a macro is used
class Derived : public Base { DECLARE_BASE(Base); DECLARE_CLONABLE(Derived);
which expands to declare the 'clone' member (with some possible compile-time checks etc.) It's a bit better than declaring/defining the whole separate member, but the programmer still needs to use it in order to accomplish the goal at hand.
V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
> Suppose that I have a hierarchy of objects which are typically > allocated dynamically and handled with some smart pointer or whatever. > However, I want to be able to create copies of those objects, while > having only a pointer-to-base-class. The solution is to write a clone() > member function like this:
> class Base > { > public: > virtual Base* clone() const { return new Base(*this); }
> // other stuff here > };
> The problem is that this clone() function must be replicated in all > the derived classes as well, and their implementation is always the > same, except for the type which is being allocated. For example:
[...]
1) You can use CRTP to avoid writing all the code again and again. 2) You can try some programming by contract to check if someone forgot to implement its clone().
> class Base > { > public: > virtual Base* clone() const { return new Base(*this); }
> // other stuff here > };
> The problem is that this clone() function must be replicated in all > the derived classes as well, and their implementation is always the > same, except for the type which is being allocated. For example:
> class Derived: public Base > { > public: > virtual Base* clone() const { return new Derived(*this); } > };
> It's not only tedious to have to write this line in each of the > derived classes, but it's also error-prone: If you ever forget to add > that line to some derived class, no compiler error will happen, and the > program will even run, but when cloning a derived object using a base > type pointer, you get a crippled copy, so the whole thing malfunctions, > and it might malfunction in a very non-obvious way which is hard to > track and debug.
> Isn't there any way of automating this process?
[...]
Odd-ball approach that comes to mind, if compile-time checking is insisted on:
class Clonable { protected: template<class T> Clonable( T const* t ) { // ensure that T implements covariant clone if ( false ) t = t->clone(); }
// OK to remove this virtual Clonable* clone() const = 0; };
class Base : protected virtual Clonable { public: Base() : Clonable( this ) { } Base* clone() const { return new Base( *this ); } };
class Derived : public Base { public: Derived() : Clonable( this ) { } Derived* clone() const { return new Derived( *this ); } };
class Error : public Derived { public: // error, Clonable doesn't have default ctor Error() /* : Clonable() */ { } };
class Error2 : public Derived { public: // error, clone() doesn't return Error2* Error2() : Clonable( this ) { } };
You could probably use a similar approach, with Clonable generating the clone function automatically, and the derived class just needing to pass 'this' to Clonable so that its template will be instantiated for the derived type.
blargg wrote: > In article <l3znl.97$zj6...@read4.inet.fi>, Juha Nieminen > <nos...@thanks.invalid> wrote: > [...] >> class Base >> { >> public: >> virtual Base* clone() const { return new Base(*this); }
>> // other stuff here >> };
>> The problem is that this clone() function must be replicated in all >> the derived classes as well, and their implementation is always the >> same, except for the type which is being allocated. For example:
>> class Derived: public Base >> { >> public: >> virtual Base* clone() const { return new Derived(*this); } >> };
>> It's not only tedious to have to write this line in each of the >> derived classes, but it's also error-prone: If you ever forget to add >> that line to some derived class, no compiler error will happen, and the >> program will even run, but when cloning a derived object using a base >> type pointer, you get a crippled copy, so the whole thing malfunctions, >> and it might malfunction in a very non-obvious way which is hard to >> track and debug.
>> Isn't there any way of automating this process? > [...]
> Odd-ball approach that comes to mind, if compile-time checking is > insisted on:
> class Clonable { > protected: > template<class T> > Clonable( T const* t ) > { > // ensure that T implements covariant clone > if ( false ) > t = t->clone();
Calling virtual function from within constructor == very bad. Besides that it looks like a rather interesting solution. I think you could improve it through something similar to boost::any:
Leave your virtual inheritance and turn Base::clone into:
Base * Base::clone() const { return static_cast<Base*>(Clonable::clone()); }
Wouldn't even need to be virtual as the polymorphism is taken care of by Clonable's pimpl.
This is untested but I'm pretty confident it, or something like it, would work. The only thing lost is the ability to construct Derived pointers without casts even when you know the Derived type. Some sort of policy based programming might do the trick there.
Noah Roberts wrote: > blargg wrote: >> [..] >> Odd-ball approach that comes to mind, if compile-time checking is >> insisted on:
>> class Clonable { >> protected: >> template<class T> >> Clonable( T const* t ) >> { >> // ensure that T implements covariant clone >> if ( false ) >> t = t->clone();
> Calling virtual function from within constructor == very bad.[..]
It's not really calling it if it's behind the 'if (false)', is it?
V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask
Noah Roberts wrote: > blargg wrote: [...] > > Odd-ball approach that comes to mind, if compile-time checking is > > insisted on:
> > class Clonable { > > protected: > > template<class T> > > Clonable( T const* t ) > > { > > // ensure that T implements covariant clone > > if ( false ) > > t = t->clone();
> Calling virtual function from within constructor == very bad. Besides > that it looks like a rather interesting solution.
Controlled by an if statement whose condition is never true == perfectly OK. The purpose is to ensure that T's clone function returns a T* (or something derived from it). This way, if T forgets to define clone, the base class version would be found and its return type wouldn't be implicitly convertible to T*.
> Leave your virtual inheritance and turn Base::clone into:
> Base * Base::clone() const { return static_cast<Base*>(Clonable::clone()); }
> Wouldn't even need to be virtual as the polymorphism is taken care of by > Clonable's pimpl.
The virtual inheritance is necessary to force the most-derived class to call the Clonable constructor with the 'this' pointer, to indirectly pass its type. BTW, you don't need any type of embedded object at all, just a function pointer:
class Base : public virtual Clonable { public: Base() : Clonable( this ) { } Base* clone() const { return static_cast<Base*> (Clonable::clone()); } };
class Derived : public Base { public: Derived() : Clonable( this ) { }
// if you forget this, user is merely inconvenienced, rather // than given Base slice of the object Derived* clone() const { return static_cast<Derived*> (Clonable::clone()); } };
> This is untested but I'm pretty confident it, or something like it, > would work. The only thing lost is the ability to construct Derived > pointers without casts even when you know the Derived type. Some sort > of policy based programming might do the trick there.
Or just forwarding functions as you mentioned. Of course I think the cost of ensuring correct clone() implementation greatly outweights the benefit, as compared to using external tests to ensure each class implements a clone in the straight-forward way:
> but it's also error-prone: If you ever forget to add > that line to some derived class, no compiler error will happen, and the > program will even run, but when cloning a derived object using a base > type pointer, you get a crippled copy, so the whole thing malfunctions, > and it might malfunction in a very non-obvious way which is hard to > track and debug.
Hi,
I'm not a c++ expert but can't we tackle this problem by having co- variant virtual functions at the derived classes ?
so it would be like
class Base { public: virtual Base* clone() const { return new Base(*this); }
// other stuff here
};
AND
class Derived: public Base { public: virtual Derived* clone() const { return new Derived(*this); } // return type is different
};
when you clone an object of the type "Derived" and try to assign it to a pointer to the type "Derived" it will fail at compile time if there is no such co-variant implementation in the derived type.
> when you clone an object of the type "Derived" and try to assign it to > a pointer to the type "Derived" it will fail at compile time if there > is no such co-variant implementation in the derived type.
If that were the case, he could simple use a copy constructor. The problem is he only has a pointer to the base class, and doesn't know the actual type. Thus, the need for a polymorphic member function to do the work for him.
blargg wrote: > Noah Roberts wrote: [...] > > This is untested but I'm pretty confident it, or something like it, > > would work. The only thing lost is the ability to construct Derived > > pointers without casts even when you know the Derived type. Some sort > > of policy based programming might do the trick there.
> Or just forwarding functions as you mentioned. Of course I think the cost > of ensuring correct clone() implementation greatly outweights the benefit, > as compared to using external tests to ensure each class implements a > clone in the straight-forward way:
> Foo* clone() const { return new Foo( *this ); }
And if you don't need covariance, you can use the non-virtual interface approach to get automatic checking at run-time:
class Base { virtual Base* clone_() const { return new Base( *this ); }
REH wrote: > On Feb 24, 7:18=A0am, tharinda...@gmail.com wrote: > > when you clone an object of the type "Derived" and try to assign it to > > a pointer to the type "Derived" it will fail at compile time if there > > is no such co-variant implementation in the derived type.
> If that were the case, he could simple use a copy constructor. The > problem is he only has a pointer to the base class, and doesn't know > the actual type. Thus, the need for a polymorphic member function to > do the work for him.
tharinda's point above is that the error of forgetting to define the derived clone() will be caught when an attempt is made to call clone() on a Derived* and assign the result to a Derived*. Catching this error is the whole point of this thread.
But even with covariant overrides of clone(), if someone clones a Derived object given just a Base*, a forgotten override of clone() in Derived won't be caught.
On Feb 25, 12:02 pm, blargg....@gishpuppy.com (blargg) wrote:
> But even with covariant overrides of clone(), if someone clones a Derived > object given just a Base*, a forgotten override of clone() in Derived > won't be caught.
that problem would be solved if you use a macro to declare and define the class methods :)
tharinda wrote: > blargg wrote: > > But even with covariant overrides of clone(), if someone clones a Derived > > object given just a Base*, a forgotten override of clone() in Derived > > won't be caught.
> that problem would be solved if you use a macro to declare and define > the class methods :)
How does defining such a macro prevent one from forgetting to invoke it?
On Feb 25, 1:53 pm, blargg....@gishpuppy.com (blargg) wrote:
> tharinda wrote: > > blargg wrote: > > > But even with covariant overrides of clone(), if someone clones a Derived > > > object given just a Base*, a forgotten override of clone() in Derived > > > won't be caught.
> > that problem would be solved if you use a macro to declare and define > > the class methods :)
> How does defining such a macro prevent one from forgetting to invoke it?
I mean if somebody is strictly adhered to a rule so that the clone function is implemented only by a macro like this
tharinda.gl wrote: > On Feb 25, 1:53=A0pm, blargg....@gishpuppy.com (blargg) wrote: > > tharinda wrote: > > > blargg wrote: > > > > But even with covariant overrides of clone(), if someone clones a Der= > ived > > > > object given just a Base*, a forgotten override of clone() in Derived > > > > won't be caught.
> > > that problem would be solved if you use a macro to declare and define > > > the class methods :)
> > How does defining such a macro prevent one from forgetting to invoke it?
> I mean if somebody is strictly adhered to a rule so that the clone > function is implemented only by a macro like this
> then there is no way you can accidentally change the return type of > the derived function.
I think you missed the main point; I'll recap since I'm not sure where we diverge. The original poster wanted to use a virtual clone() in the base class, but wanted a way to catch the error of forgetting to override it in derived classes, even multiple levels deep (where making the base function pure wouldn't help). He wanted a compile-time error, but I've generalized that to reliably getting SOME kind of error.
You noted that with covariant return types, this error will be caught in some cases at compile-time:
class Base { public: virtual Base* clone() const { return new Base( *this ); } };
class Derived : public Base { public: virtual Derived* clone() const { return new Derived( *this ); } };
class Error : public Base { public: // forgot clone() };
void user( Base* b, Derived* d, Error* e ) { d = d->clone(); // OK e = e->clone(); // error, since e.clone() returns a Base*
b = b->clone(); // OK, even if b points to an Error object }
If an error object were only ever cloned via a Base*, the error would never be reliably caught. Thus, using covariant returns isn't sufficient to reliably catch the error of a forgotten clone() override. Using a macro to automate the declaration/definition of derived clone() doesn't do anything to prevent the derived class author from forgetting to invoke it. My point about using a Base* in the quoted message wasn't about the derived class author overriding clone() wrong; it was about him not overriding it at all, and users cloning entirely through Base*.
blargg wrote: > tharinda.gl wrote: > > On Feb 25, 1:53=A0pm, blargg....@gishpuppy.com (blargg) wrote: > > > tharinda wrote: > > > > blargg wrote: > > > > > But even with covariant overrides of clone(), if someone clones a Der= > > ived > > > > > object given just a Base*, a forgotten override of clone() in Derived > > > > > won't be caught.
> > > > that problem would be solved if you use a macro to declare and define > > > > the class methods :)
> > > How does defining such a macro prevent one from forgetting to invoke it?
> > I mean if somebody is strictly adhered to a rule so that the clone > > function is implemented only by a macro like this
> > then there is no way you can accidentally change the return type of > > the derived function.
> I think you missed the main point; I'll recap since I'm not sure where > we diverge. The original poster wanted to use a virtual clone() in the > base class, but wanted a way to catch the error of forgetting to > override it in derived classes, even multiple levels deep (where making > the base function pure wouldn't help). He wanted a compile-time error, > but I've generalized that to reliably getting SOME kind of error.
> You noted that with covariant return types, this error will be caught in > some cases at compile-time:
> class Base { > public: > virtual Base* clone() const { return new Base( *this ); } > };
> class Derived : public Base { > public: > virtual Derived* clone() const { return new Derived( *this ); } > };
> class Error : public Base { > public: > // forgot clone() > };
> void user( Base* b, Derived* d, Error* e ) > { > d = d->clone(); // OK > e = e->clone(); // error, since e.clone() returns a Base*
> b = b->clone(); // OK, even if b points to an Error object > }
> If an error object were only ever cloned via a Base*, the error would > never be reliably caught. Thus, using covariant returns isn't sufficient > to reliably catch the error of a forgotten clone() override. Using a > macro to automate the declaration/definition of derived clone() doesn't > do anything to prevent the derived class author from forgetting to > invoke it. My point about using a Base* in the quoted message wasn't > about the derived class author overriding clone() wrong; it was about > him not overriding it at all, and users cloning entirely through Base*.
> Sorry for the verbosity.
blargg, Yes you are correct, my solution won't be a concrete method of finding whether the developer has forgotten to implement the clone method at the derived class. I assumed following things in my solution.
1. If we don't have the definition of the Derived class then there is no point of making sure the created object is really a object of the derived type since we only have access to the base type. This may not be true for all the cases.
2. If you want to do some kind of down-casting then you have to worry about the actual data type at that point.
2. If you have the definition of the derived type then you can always use a pointer to to that type in order to get the cloned object (so that the compiler error would be generated if there is no such overridden method).
3. You can make sure the return type always refers to the most derived type by using some kind of a macro.
As I have mentioned earlier, I am not a c++ pro and still learning this marvelous language. I really appreciate on the effort that you people are putting in order improve our knowledge.
> blargg, Yes you are correct, my solution won't be a concrete method of > finding whether the developer has forgotten to implement the clone > method at the derived class. I assumed following things in my > solution.
> 1. If we don't have the definition of the Derived class then there is > no point of making sure the created object is really a object of the > derived type since we only have access to the base type. This may not > be true for all the cases.
In fact, it is extremely rare that this assumption would be true. In general, if you have T* orig; T* p_new; //... p_new = orig->clone(); then most programmers will assume that orig->do_something(); and p_new->do_something(); will have exactly the same effect on their respective objects.
It does not matter that you don't know about the additional functions that a derived class exposes. The expectation is that the virtual functions that you call (indirecly) through the Base interface resolve to the same functions.
> On Feb 25, 12:53=A0pm, tharinda...@gmail.com wrote: > > blargg, Yes you are correct, my solution won't be a concrete method of > > finding whether the developer has forgotten to implement the clone > > method at the derived class. I assumed following things in my > > solution.
> > 1. If we don't have the definition of the Derived class then there is > > no point of making sure the created object is really a object of the > > derived type since we only have access to the base type. This may not > > be true for all the cases.
> In fact, it is extremely rare that this assumption would be true. > In general, if you have > T* orig; > T* p_new; > //... > p_new =3D orig->clone(); > then most programmers will assume that > orig->do_something(); > and > p_new->do_something(); > will have exactly the same effect on their respective objects.
> It does not matter that you don't know about the additional functions > that a derived class exposes. The expectation is that the virtual > functions that you call (indirecly) through the Base interface resolve > to the same functions.
Besides, if you really didn't mind a Base slice of the object, you wouldn't even need a clone function:
void user( Base const& b ) { Base slice( b ); ... }
Actually, thinking about it more I'm pretty confident that this interface could be further extended so that the clone functionality isn't even in the class you're using and you could use ANY inheritance tree in this manner. This would be the optimal design in many cases.
You would simply implement this as a sort of smart pointer that does deep-cloning on whatever object it points to. Should be relatively straightforward to implement using the techniques in the above so I'm not going to do so here.
What would be really nice is a policy based smart pointer that you could add this functionality to as a policy. Might look into Loki to see if it's there already.
> I'm sure this is a frequently asked question, but... > Suppose that I have a hierarchy of objects which are typically > allocated dynamically and handled with some smart pointer or > whatever. However, I want to be able to create copies of > those objects, while having only a pointer-to-base-class. The > solution is to write a clone() member function like this: > class Base > { > public: > virtual Base* clone() const { return new Base(*this); }
> // other stuff here > }; > The problem is that this clone() function must be replicated > in all the derived classes as well, and their implementation > is always the same, except for the type which is being > allocated. For example: > class Derived: public Base > { > public: > virtual Base* clone() const { return new Derived(*this); } > }; > It's not only tedious to have to write this line in each of > the derived classes, but it's also error-prone: If you ever > forget to add that line to some derived class, no compiler > error will happen, and the program will even run, but when > cloning a derived object using a base type pointer, you get a > crippled copy, so the whole thing malfunctions, and it might > malfunction in a very non-obvious way which is hard to track > and debug. > Isn't there any way of automating this process? (And without > making the base class a template class, which would be rather > tedious if the base class is large, especially since we don't > have export templates in practice.)
I would imagine some development tools would have a means of automatically generating the function. Otherwise, blargg and Noah Roberts have proposed an interesting solution, albeit with some runtime overhead (an additional dynamic allocation---probably not significant for the types of things which usually get cloned). But is the extra code really a problem? It's not that much. The "classical" solution settles for a runtime check:
class Base { public: Base* clone() const { Base* result = doClone() ; assert( typeid( *result ) == typeid( *this ) ) ; return result ; }
private: virtual Base* doClone() const = 0 ; } ;
(Actually, the classical solution doesn't do anything special. In practice, I've never found forgetting to implement the clone function in a derived class to be a real problem. All the more so in that hierarchies which support cloning rarely contain classes which derive from a concrete type anyway, so making clone() pure virtual in the base class suffices to ensure a compiler error.)
-- James Kanze (GABI Software) email:james.ka...@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34