In C++ we can do this:
struct Base { virtual Base* Clone() const { ... } virtual ~Base(){} }; struct Derived : Base { virtual Derived* Clone() const {...} //overrides Base::Clone };
However, the following won't do the same trick:
struct Base { virtual shared_ptr<Base> Clone() const { ... } virtual ~Base(){} }; struct Derived : Base { virtual shared_ptr<Derived> Clone() const {...} //hides Base::Clone };
In this example Derived::Clone
hides Base::Clone
rather than overrides it, because the standard says that the return type of an overriding member may change only from reference(or pointer) to base to reference (or pointer) to derived. Is there any clever workaround for this? Of course one could argue that the Clone
function should return a plain pointer anyway, but let's forget it for now - this is just an illustratory example. I am looking for a way to enable changing the return type of a virtual function from a smart pointer to Base
to a smart pointer to Derived
.
Thanks in advance!
Update: My second example indeed doesn't compile, thanks to Iammilind
C++'s classical OOP system supports “covariant return types,” but it does not support “contravariant parameter types.”
RAII stands for Resource Acquisition Is Initialization. The idea behind this idiom: for any resource acquired, an object should be initialized that will own that resource and close it in the destructor. Smart pointers are a prominent example of RAII . They help avoid memory leaks.
As shown in the example, a smart pointer is a class template that you declare on the stack, and initialize by using a raw pointer that points to a heap-allocated object.
Shared pointers are smart pointers that keep a count of how many instances of the pointer exist, and only clean up the memory when the count reaches zero. In general, only use shared pointers (but be sure to use the correct kind--there is a different one for arrays).
You can't do it directly, but there are a couple of ways to simulate it, with the help of the Non-Virtual Interface idiom.
struct Base { private: virtual Base* doClone() const { ... } public: shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); } virtual ~Base(){} }; struct Derived : Base { private: virtual Derived* doClone() const { ... } public: shared_ptr<Derived> Clone() const { return shared_ptr<Derived>(doClone()); } };
This only works if you actually have a raw pointer to start off with.
struct Base { private: virtual shared_ptr<Base> doClone() const { ... } public: shared_ptr<Base> Clone() const { return doClone(); } virtual ~Base(){} }; struct Derived : Base { private: virtual shared_ptr<Base> doClone() const { ... } public: shared_ptr<Derived> Clone() const { return static_pointer_cast<Derived>(doClone()); } };
Here you must make sure that all overrides of Derived::doClone
do actually return pointers to Derived
or a class derived from it.
In this example
Derived::Clone
hidesBase::Clone
rather than overrides it
No, it doesn't hide it. Actually, it's a compilation error.
You cannot override nor hide a virtual function with another function that differs only on return type; so the return type should be the same or covariant, otherwise the program is illegal and hence the error.
So this implies that there is no other way by which we can convert shared_ptr<D>
into shared_ptr<B>
. The only way is to have B*
and D*
relationship (which you already ruled out in the question).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With