Suppose that I have a class B
.
B
is a container of a single field C c;
.
C
is designed to be a base class. It is the super class of C1
,C2
, etc.
class C{
public: int dummy=3;
public: virtual void print(){ std::cout<<"I am C"<<std::endl; }
};
class C2: public C{
public: virtual void print(){ std::cout<<"I am C2"<<std::endl; }
};
class B{
public: ??? c; //C or C* or std::unique_ptr or ....
};
Question
Which is a suitable data type of a light-weight field c
that :-
(#1) c
can also hold an instance of a derive class e.g. C2
.
(#2) The field c
is automatically copied by value when calling B::operator=()
or default B
's copy constructor, so no custom functions are required.
(#3) c
is automatically deleted when B
is deleted, so no B
's custom destructor is required.
Roughly speaking, here is what I expect :-
int main(){
B b1;
b1.c = C2(); //(#1)
B b2=b1; // b2.c should be another copy of b.c
b2.c.dummy = 3; //(#2) b.c should not be effected
//(#3) both b1.c and b2.c are deleted, no memory leak
}
It is very useful for prototyping (prototype-pattern), where I want to copy many objects and customize each of them with high flexibility and minimum human-error (because no need to maintain either copy-constructor
or operator=()
).
My poor solutions
Version 1 (C*)
#include <iostream>
class C{
public: virtual void print(){ std::cout<<"I am C"<<std::endl; }
};
class C2: public C{
public: virtual void print(){ std::cout<<"I am C2"<<std::endl; }
};
class B{
public: C* c;
};
int main(){
B b1;
b1.c = new C2();
B b2=b1;
}
The approach does not meet the requirement :-
- violate (#2): In
B b2=b;
,b.c
is shallow copy. I want deep copy. - violate (#3): I have to delete
b.c
manually, or add such statement inB
's destructor.
Version 2 (std::unique_ptr)
class B{
public: std::unique_ptr<C> c=nullptr;
};
int main(){
B b1;
b1.c = std::make_unique<C2>();
B b2=b1;
}
This is not compilable because default B::operator=()
no longer work.
I have to manually code B::operator=()
.
I don't want to code it manually, because it is (human-)error-prone. (violate (#2))
Version 3 (new customize class)
Encapsulate C inside a custom class that do exactly what I want.
Here is a draft :-
template<class T> CrazyCopy{
T* t;
// write some custom operator=, custom constructor, custom destructor
};
class B{
public: CrazyCopy<C> c;
};
I think it is overkill. (?)