Clone derived class from base class pointer
I also think you probably cannot improve the code in the sense to make it shorter.
I would say this implementation is basically the way to go.
What you could do is to change the return value of Derived::clone
to Derived *
. Yes C++ allows this.
Then a direct use of Derived::clone
yields the correct pointer type and Base::clone
still works as expected
class Derived : public Base
{
public:
Derived()
{
a = 8;
}
Derived* vclone() const override // <<--- 'Derived' instead of 'Base'.
{
return new Derived(*this);
}
};
I would also rename to vclone
member function to clone
(There is no need to have two names).
The free function clone
could be made a template so that it works for all classes and returns the right pointer type
template <class T>
T *clone(const T *cls)
{
return cls->clone();
}
However, all these changes do not make the code shorter, just more usable and perhaps more readable.
To make it a little shorter you might use an CRTP approach.
template <class Derived, class Base>
class CloneHelper: public Base {
Derived* vclone() const override
{
return new Derived(* static_cast<Derived *>(this) );
}
};
// then use
class Derived : public CloneHelper<Derived, Base>
{
public:
Derived()
{
a = 8;
}
};
However, I am not sure if it is worth it. One still must not forget the CloneHelper
, it makes inheritance always public
and you cannot delegate to the Base
constructor so easily and it is less explicit.
C++ elegantly clone derived class by calling base class
You could always stick all the cloning logic into its own class in the middle of the hierarchy:
template <class Derived, class Base>
class CloneCRTP : public Base {
public:
Derived* clone() const override {
return new Derived(static_cast<Derived const&>(*this));
}
};
And then:
class B : public CloneCRTP<B, A>
{
int i;
public:
virtual ~B() { cout << "destroyed b" << endl; }
};
No more boilerplate.
Clone derived class from base class method
Just override the Clone
and have another method to CreateInstance
then do your stuff.
This way you could have only Base
class avoiding generics.
public Base
{
protected int field1;
protected int field2;
....
protected Base() { ... }
public virtual Base Clone()
{
var bc = CreateInstanceForClone();
bc.field1 = 1;
bc.field2 = 2;
return bc;
}
protected virtual Base CreateInstanceForClone()
{
return new Base();
}
}
public A : Base
{
protected int fieldInA;
public override Base Clone()
{
var a = (A)base.Clone();
a.fieldInA =5;
return a;
}
protected override Base CreateInstanceForClone()
{
return new A();
}
}
Cloning a derived type more elegantly
You could use the CRTP:
template <typename Derived>
struct derived_base : base
{
Derived* clone()
{
Derived* x = new Derived;
// ...
return x;
}
};
struct derived : derived_base<derived> {}
C++: Deep copying a Base class pointer
You need to use the virtual copy pattern: provide a virtual function in the interface that does the copy and then implement it across the hierarchy:
struct base {
virtual ~base() {} // Remember to provide a virtual destructor
virtual base* clone() const = 0;
};
struct derived : base {
virtual derived* clone() const {
return new derived(*this);
}
};
Then the DeepCopy
object just needs to call that function:
class DeepCopy
{
Base * basePtr;
public:
DeepCopy(DeepCopy const & dc) // This should be `const`
: basePtr( dc.basePtr->clone() )
{}
};
Related Topics
How to Write C/C++ Code Correctly When Null Pointer Is Not All Bits Zero
Check Traits for All Variadic Template Arguments
Do Class/Struct Members Always Get Created in Memory in the Order They Were Declared
Check Variadic Templates Parameters for Uniqueness
Overloading Operator<<: Cannot Bind Lvalue to 'Std::Basic_Ostream<Char>&&'
How Does One Securely Clear Std::String
Why Does Windows 10 Start Extra Threads in My Program
How to Use Createfile, But Force the Handle into a Std::Ofstream
Stack Overflow Caused by Recursive Function
Hide User Input on Password Prompt
How to Write an Eof Character Ourselves
Gcc C++ "Hello World" Program -> .Exe Is 500Kb Big When Compiled on Windows. How to Reduce Its Size
Why Is It Allowed to Pass R-Values by Const Reference But Not by Normal Reference