As Scott Myers wrote, you can take advantage of a relaxation in C++'s type-system to declare clone() to return a pointer to the actual type being declared:
class Base
{
virtual Base* clone() const = 0;
};
class Derived : public Base
{
virtual Derived* clone() const
};
The compiler detects that clone() returns an pointer to the type of the object, and allows Derived to override it to return a pointer to derived.
It would desirable to have clone() return a smart pointer that implies transfer of ownership semantics, like the following:
class Base
{
virtual std::auto_ptr<Base> clone() const = 0;
};
class Derived : public Base
{
virtual std::auto_ptr<Derived> clone() const;
};
Unfortunately, the relaxation of the conventions does not apply to templated smart pointers, and the compiler will not allow the override.
So, it seems I am left with two options:
Have clone() return a "dumb" pointer, and document that clients are responsible for disposing of it.
Have clone() return a smart base pointer, and have clients use dynamic_cast to save them to a Derived pointer if they need it.
Is one of these approaches preferred? Or is there a way for me to eat my transfer of ownership semantics and have my strong type safety too?
Use the Public non-virtual / Private virtual pattern :
class Base {
public:
std::auto_ptr<Base> clone () { return doClone(); }
private:
virtual Base* doClone() { return new (*this); }
};
class Derived : public Base {
public:
std::auto_ptr<Derived> clone () { return doClone(); }
private:
virtual Derived* doClone() { return new (*this); }
};
The syntax isn't quite as nice, but if you add this to your code above, doesn't it solve all your problems?
template <typename T>
std::auto_ptr<T> clone(T const* t)
{
return t->clone();
}
I think the function semantics are so clear in this case that there is little space for confusion. So I think you can use the covariant version (the one returning a dumb pointer to the real type) with an easy conscience, and your callers will know that they are getting a new object whose property is transferred to them.
It depends on your use case. If you ever think you will need to call clone on a derived object whose dynamic type you know (remember, the whole point of clone is to allow copying without knowing the dynamic type), then you should probably return a dumb pointer and load that into a smart pointer in the calling code. If not, then you only need to return a smart_ptr and so you can feel free to return it in all overrides.
Tr1::shared_ptr<> can be casted like it were a raw pointer.
I think have clone() return a shared_ptr<Base> pointer is a pretty clean solution. You can cast the pointer to shared_ptr<Derived> by means of tr1::static_pointer_cast<Derived> or tr1::dynamic_pointer_cast<Derived> in case it is not possible to determine the kind of cloned object at compile time.
To ensure the kind of object is predictible you can use a polymorphic cast for shared_ptr like this one:
template <typename R, typename T>
inline std::tr1::shared_ptr<R> polymorphic_pointer_downcast(T &p)
{
assert( std::tr1::dynamic_pointer_cast<R>(p) );
return std::tr1::static_pointer_cast<R>(p);
}
The overhead added by the assert will be thrown away in the release version.
That's one reason to use boost::intrusive_ptr instead of shared_ptr or auto/unique_ptr. The raw pointer contains the reference count and can be used more seamlessly in situations like this.
Updating MSalters answer for C++14:
#include <memory>
class Base
{
public:
std::unique_ptr<Base> clone() const
{
return do_clone();
}
private:
virtual std::unique_ptr<Base> do_clone() const
{
return std::make_unique<Base>(*this);
}
};
class Derived : public Base
{
private:
virtual std::unique_ptr<Base> do_clone() const override
{
return std::make_unique<Derived>(*this);
}
}
You could have two methods, a virtual clone() that returns a smart pointer wrapper around the base type, and a non-virtual clone2() that returns the correct type of smart pointer.
clone2 would obviously be implemented in terms of clone and encapsulate the cast.
That way can get the most derived smart pointer that you know at compile time. It may not be the most derived type overall, but it uses all the information available to the compiler.
Another option would be to create a template version of clone that accepts the type you are expecting, but that adds more burden on the caller.
Related
For the "rule of zero", I understand that I want to separate data management out into simple classes implementing rule of 3, rule of 5, whatever, so that the the more complicated classes can use constructors, assignment operators, etc, as automatically provided.
How does this work when a class member has to be a pointer because of polymorphism?
E.g., suppose I have a class
class MyClass{
private:
s_array<int> mynumbers;
s_array<double> mydoubles;
Base * object;
...
};
Here, Base is a base class with multiple derived classes, and object may be point to one of the derived classes. So object is a pointer in order to get polymorphism.
If it wasn't for the presence of this Base pointer, I could use the rule-of-zero for MyClass assuming s_array<> is properly implemented. Is there a way to set things up so that MyClass can use the rule of zero, even though object is a pointer? The behavior that I want on copy is that a new instance of MyClass gets a pointer to a new copy of object.
If you want to apply the rule of 0 with pointers, you need to use a shared pointer:
shared_ptr<Base> object;
However this doesn't fully fulfil your requirement. Because shared_ptr will provide for the rule of 5, but the copied pointers will always point to the same original object.
To get the behavior that you want, you'd need to create your own smart pointer that provides for the rule of 3 or 5.
If multiple MyClass objects can point to the same Base object, then simply use std::shared_ptr<Base> instead of Base* for your object member, as other responders mentioned.
But, if each MyClass object needs to point to its own Base object, then you have no choice but to implement the Rule of 3/5 in MyClass so that it can create its own Base object and/or clone a Base object from another MyClass object.
Just for the record, what I using to solve this is the following (basically as suggested as above):
template <class myClass>
class clone_ptr
{
public:
clone_ptr(){location=nullptr;}
clone_ptr(myClass* d) { location = d;}
~clone_ptr() { delete location; }
clone_ptr(const clone_ptr<myClass>& source){
if (source.location!=nullptr){
location=source.location->Clone();
}
else
location=nullptr;
}
clone_ptr& operator= (const clone_ptr<myClass>& source){
if (&source!=this){
if (source.location!=nullptr){
location=source.location->Clone();
}
else
location=nullptr;
}
return *this;
}
myClass* operator->() { return location; }
myClass& operator*() { return *location; }
private:
myClass* location;
};
I am implementing the Clone() function in the appropriate classes as follows:
class myClass : public parentClass{
...
public:
myClass* Clone()
{
return new myClass(*this);
}
I'm using the llvm library and I want to check if an llvm::Value * is actually an llvm::LoadInst * (llvm::LoadInst is inherited from llvm::Value).
But sadly, llvm::Value doesn't contain any virtual method! (Yes, even without virtual destructor) Is it possible to use dynamic_cast on a class without virtual methods, or is there any other way to do the type checking?
In LLVM, there is a llvm::dyn_cast<T> that will use LLVM's internal constructs to dynamically cast from one type to another, as long as they are indeed valid casts - if you use the wrong type T, it will return a nullptr.
So something like:
llvm::Value *v = ... some code here ...
...
llvm::LoadInst* li = llvm::dyn_cast<llvm::LoadInst>(v);
if (!li) { ... not a LoadInst, do whatever you should do here ... }
else { ... use li ... }
Naturally, if you already DO know that v is a LoadInst, you don't need to check - but an assert(li && "Expected a LoadInst"); will catch if you ever got that wrong.
Note that you don't use T* for llvm::dyn_cast<T>, as you would for the C+++ standard dynamic_cast.
This comment in the code for llvm::Value explains that there is no vtable exactly for this reason (http://www.llvm.org/doxygen/Value_8h_source.html#l00207)
/// Value's destructor should be virtual by design, but that would require
/// that Value and all of its subclasses have a vtable that effectively
/// duplicates the information in the value ID. As a size optimization, the
/// destructor has been protected, and the caller should manually call
/// deleteValue.
~Value(); // Use deleteValue() to delete a generic Value.
Is it possible to use dynamic_cast on a class without virtual methods,
There is no way to use dynamic_cast if the input is not pointer or reference to a polymorphic type, i.e. does not have any virtual member functions.
or is there any other way to do the type checking?
I can't think of any. Your best option is to use static_cast but then you must be very certain that the type to which you are casting is valid.
struct Base { ... };
struct Derived1 : Base { ... };
struct Derived2 : Base { ... };
void foo(Base* base)
{
Derived1* ptr = static_cast<Derived1*>(base);
// Use ptr
}
void bar()
{
foo(new Derived1()); // OK.
foo(new Derived2()); // Not OK since foo assumes that the pointer
// really points to a Derived1 object.
}
I am interested in whether it is possible to return a pointer to the derived class from a method defined in the base class without explicitly casting it to the derived class. The idea is that the receiver receives a pointer to the derived class through a pointer to base class and treats it as if it were a derived class through polymorphism.
For example, it is possible to do this:
template<typename TClassType>
class A
{
public:
virtual std::shared_ptr<TClassType const> execute(void)
{
return std::shared_ptr<TClassType const>
(static_cast<TClassType*>(this));
}
};
Here, the derived class is being passed as the template argument.
However, what I would like to do is something similar to this:
template<typename TBaseClassType>
class A
{
public:
virtual std::shared_ptr<TBaseClassType const> execute(void)
{
return this;
}
};
I would like to do it in such a way that the returned pointer to base is still polymorphic with respect to the original derived class. TBaseClassType could be class A, but could also be in between class A and the derived class in the inheritance tree, i.e. A->TBaseClassType->Derived. Derived is the class from which execute() is called.
Note 1: it has to be a pointer to const (can also be a const pointer to const).
Note 2: I understand why this particular solution cannot work and I am interested if anyone knows of ways around the problem, rather than the direct approach.
EDIT. The solution I decided to use is summarised in my last comment for the accepted answer.
Firstly, there are covariant returntypes. This means that e.g. a clone() function can be defined to return a base* in the baseclass and to return a derived* in the derived class. This is not your problem though, because the two types shared_ptr<base> and shared_ptr<derived> are not covariant, they are completely unrelated. There are ways around that, but they require a bit of work:
class base
{
public:
smart_ptr<base> clone() const
{ return smart_ptr<base>(this->do_clone()); }
private:
virtual base* do_clone()
{ return new base(*this); }
};
As you see, the public function returning a smart pointer calls the private virtual function that returns a raw pointer and which can use covariant returntypes. Now the derived class:
class derived: public base
{
public:
smart_ptr<derived> clone() const
{ return smart_ptr<derived>(this->do_clone()); }
private:
virtual derived* do_clone()
{ return new derived(*this); }
};
This class pretty much contains the similar code, only that it derives from base. Now, if you have a reference (or pointer/smart pointer) to the derived class, calling clone() on it will give you a pointer of the right type. Calling it on a reference to the baseclass will give you a pointer who's static type is base but who's dynamic type is still the correct derived class. This works because the lookup of memberfunction stops in the most derived class that implements the function and then stops. So basically this is a mixture of overriding virtual functions and hiding functions in the baseclass.
Notes:
I wrote "smart_ptr" intentionally, even though you wrote shared_ptr, because for this particular example, using auto_ptr (C++98) or unique_ptr (C++11) would be a better choice since no references are shared.
When implementing clone(), I would also assert() that the pointer returned by do_clone() is non-null and that it points to the same dynamic type as this using typeid. If that assertion fires, someone forgot to override do_clone() in a derived class.
You can not return the derived type in the baseclass, because that would require a dependency cycle and because it is not at all sure that the base object is also a derived object.
You could create a template function that you would pass the expected type and which then dynamic_casts to the requested type, I'll leave that decision to you. The syntax would then be like derived* derived_ptr = base_ptr->execute<derived>(), I think.
So I want to override the pure abstract method in my derived classes but I got this error. Can someone help me see what happened and how can I complete it.
My Device class;
class Device {
public:
Device();
Device(const Device& orig);
virtual ~Device();
virtual Device Clone() = 0;
}
And my derived class;
class Radar : public Device {
public:
Radar();
// Radar(const Radar& orig); // commenting so the compiler using its default copy constructor
virtual ~Radar();
Radar Clone();
};
Source file for my Radar class;
Radar Radar::Clone() {
return *(new Radar(*this));
}
If I use Device type in my Clone method in Device class, it will pop-up that Device is an abstract class.
If I use void type (which I'm assuming it's not what I want to have), it will show that I haven't implement this method.
What should I do?
Your Clone method will need to return pointers to the cloned objects... covariant return types only work that way (as returning by value is asking the caller to copy the returned value to the stack - that would be a memory leak when you've allocated it with new).
So, it should be:
virtual Device* Clone() = 0;
...and later...
Radar* Clone(); // YES, it should be Radar* here - that uses C++'s support for
// "covariant return types", see also "UPDATE" discussion
Radar* Radar::Clone()
{
return new Radar(*this);
}
UPDATE - further explanation as requested
So, the idea with a clone function is that it can return a deep copy of whatever actual derived type your Device* is currently addressing. Given that derived type might add data members that Device lacked, it could be a larger object, and the caller has no ability to reserve the right amount of stack space in which to store it. For that reason, the object needs to be allocated dynamically with new, and the predictably-sized Device* is the caller's way to access the new object. It's legal for the clone function to return a Radar* though - all that means is that client code that knows at compile time that it is dealing with a Radar and clones it can continue to use it as a Radar - accessing any extra members that Radar provides.
Hope that helps clarify things. You might also want to do some background reading on Object Oriented programming.
A classic approach to implementing this cloning technique is to use covariant return types for the Clone() method. Coupled with modern RAII techniques (e.g. unique_ptr et. al.) it offers a very flexible and safe combination to manage and clone the objects appropriately.
One of the advantages of the covariant return type is that you are able to obtain a clone an object (a deep copy) and the return type is at the same level in the hierarchy as the argument (i.e. the return is not always to the base class) and no immediate casting is required. In C++, pointers and references support covariance, values do not support covariance.
Using a smart pointer such as unique_ptr is advised over raw painters to avoid memory leaks. The clone_unique factory is modelled on the corresponding make_unique utility from the standard library and returns a unique_ptr. It contains explicit type checks on the class hierarchy of the argument and target types.
The solution does require use of std::unique_ptr. If not available with your compiler, boost provides alternatives for these. There are a few other newer C++ language features, but these can be removed if required.
#include <type_traits>
#include <utility>
#include <memory>
class Device {
public:
virtual Device* Clone() const = 0;
};
class Radar : public Device {
public:
virtual Radar* Clone() const override {
// ^^^^^^ covariant return compared to Device::Clone
return new Radar(*this);
}
};
// Clone factory
template <typename Class, typename T>
std::unique_ptr<Class> clone_unique(T&& source)
{
static_assert(std::is_base_of<Class, typename std::decay<decltype(*source)>::type>::value,
"can only clone for pointers to the target type (or base thereof)");
return std::unique_ptr<Class>(source->Clone());
}
int main()
{
std::unique_ptr<Radar> radar(new Radar());
std::unique_ptr<Device> cloned = clone_unique<Device>(radar);
}
Sample code.
See this related answer for a longer example.
Please try the following signature
virtual Device& Clone() = 0;
or
virtual Device* Clone() = 0;
//Body
Device& Radar::Clone() {
return Radar(*this));
}
Here is my test example:
struct base {
virtual ~base(){}
int x;
};
struct derived: public virtual base {
base * clone() {
return new derived;
}
derived(): s("a") {}
std::string s;
};
int main () {
derived d;
base * b = d.clone();
derived * t = reinterpret_cast<derived*>(b);
std::cout << t->s << std::endl;
return 0;
}
It crashes at the line where I print s. Since "b" is a pointer to the derived class, reinterpret_cast should just work. I wonder why it crashes. At the same time, if I replace reinterpret_cast with dynamic_cast, then it works.
Even if b is here dynamically of type derived, you have to use dynamic_cast. This is what dynamic_cast is for, to dynamically convert a pointer of a base class into a derived class at runtime.
reinterpret_cast takes the raw pointer and considers it as being of the derived type. However, because of the virtual inheritance, a slight adjustment must be done to the pointer to point to the correct method dispatch table, and that's precisely what dynamic_cast will do.
Don't reinterpret_cast it, it will cause trouble with multiple or virtual inheritance, like in your case. Wont a simply static_cast do the job here?
To know why, search for implementations of virtual inheritance. A common one is to store a pointer to the base class within the object, so the virtual base does not share the same address than its derived classes. There is a similar case when multiple inheritance is used.
In short, reinterpret_cast can't do much more than casting pointers to ints and back (if there is enough size in the int to contain a pointer).
As the other answers here suggested, you cannot use reinterpret_cast in this fashion because the value of the pointer to base actually differs from the value of the pointer to derived. The valid pointer is deduced at runtime which is why you have to use dynamic_cast. static_cast cannot work, as you don't know at designtime through which intermediate type the most derived class (the one you want to cast to) was derived from the type you have a pointer to.
The real question here should be: I know at design time, how to compute the derived pointer from the base pointer. How can the runtime penalty (of dynamic_cast) be avoided?
Frankly, I don't see a really good option here, but a possible option is to store the pointer to the most derived type in a constant pointer inside the root class, like so:
struct base {
void* const self;
virtual ~base() {}
protected:
base(void* self) : self(self) {}
};
struct derived : public virtual base {
derived() : base(this) {}
}
This is ugly and dangerous, because it sacrifices type safety for performance (if you are really lucky, you get a slight runtime performance out of it). But you will be able to reinterpret_cast your base pointer (the self member of type void*) into a derived pointer.