I have a class(let's call it A) and I want to copy A. So I call A's copy constructor. A has a member of type B* which is a pointer of type B to one of his subclasses.(let's call them B with a number. (ie: B1, B5, ..))
Since I don't want to just copy the address, I call memberofA->copyconstructor from one of the subclasses. The copy constructor in the base class is called from within the copy constructor of the subclass. But is this possible or do i need to dynamic cast the pointer of type baseclass to the correct subclass the pointer is pointing too?
class A {
public:
A(const A& object) {
// what should i call here to deep copy member
}
private:
B* member //pointer to subclass of B
};
class B {
privatedatamamber
public:
B (const B& object) {
privatedatamember = object->getprivatedatamember();
}
};
class B1 : public B {
privatedatamember
public:
B1 (const B1& object) : B(object) {
privatedatamember = object->getprivatedatamember();
}
};
The approach I'd use is to give B an abstract method clone() returning a std::unique_ptr<B> which is implemented in every concrete class to return a copy, e.g.:
std::unique_ptr<B> D::clone() const {
return std::unique_ptr<B>(new D(*this));
}
When a deep copy is needed you can then just call clone().
Add a public function to B:
virtual B* Clone() = NULL;
B's subclasses must implement this (pure virtual function).
Here's an example:
B header:
virtual B* Clone() = 0; //public
B1 header:
virtual B* Clone();
B1 cpp:
B* B1::Clone()
{
return new B1(*this);
}
A:
A::A(const A& object) : member(object.member->Clone()) {
}
Related
I have a base class that holds a vector of pointers to derived classes and a virtual recursive method like this:
class Base
{
std::vector<Base*> vec;
public:
Base(std::vector<Base*> vec = {}) : vec {vec} {}
virtual ~Base() = default;
virtual void f() const
{
if (vec.size() == 0)
throw std::logic_error("Last children should implement f()")
for (auto * part : vec)
part->f();
}
}
The method f() is recursive and the last child of Base should override it. For example the following works
Where the first derived class is
class B : public Base
{
B() : Base() {}
virtual void f() const
{
std::cout << "In B\n";
}
}
class A : public Base
{
B b_,c_;
public:
A(B b, B c) : Base({&b_,&c_}), b_ {b}, c_{c} {}
}
If I call
B b,c;
A a(b,c);
a.f()
It will print twice "In B"correctly. Notice that A does not override f() so Base::f() is called, this loops and calls B::f() twice, once for b and once for c. However if I go one nested class more, for example by having
class C : public Base
{
A a_;
B b_;
public:
C(A a, B b): Base({&a_, &b_}), a_{a}, b_{b} {}
}
And I call C::f() the program segfaults. I suppose this is because there are some temporaries and their destructors delete the pointers held by Base. Is the solution to this to hold shared_ptr? or is there a better design? I cannot hold unique_ptr cause that would make all derived classes not copyable.
public C(A a, B b): Base({&a, &b}), a{a}, b{b} {}
Firstly, you can't have public there.
Your base points to the parameters of the constructor. Those parameters are destroyed when the constructor finishes and the pointers become invalid. Point to the members instead:
C(A a, B b): Base({&this->a, &this->b}), a{a}, b{b} {}
Note however that the implicit copy and move constructors and assignment operators of the class are broken because they will make the copied object point to the members of the copy source, rather than the members of the copy itself. So, you'll need implement those as well.
is there a better design?
Possibly a better approach: Instead of storing the pointers in the base sub object, write a virtual function that derived classes can override, and which returns a range of pointers to children.
I have the following working example, where I am passing an object of type Derived to a constructor that expects an object of type Bridge:
#include <iostream>
class Base {
public:
Base() {};
virtual Base* clone() const = 0;
virtual ~Base() {};
};
class Derived : public Base {
public:
Derived() {};
virtual Base* clone() const {
std::cout << "Cloned derived\n";
return new Derived(*this);
}
virtual ~Derived() {}
};
class Bridge {
public:
Bridge(const Base& b_) {
b = b_.clone();
std::cout << "Cloned b\n";
};
~Bridge() {}
private:
Base *b;
};
class Test {
public:
Test(const Bridge& b_) : b(b_) {};
private:
Bridge b;
};
int main()
{
Derived d;
Test t(d);
}
Why is this allowed? From what I can gather it works because of Bridge's constructor that takes a reference to a Base object. But I have a hard time figuring out what the order actually is.
Is the following timeline of what goes on correct?
The statement Test t(d); implies we have Bridge& b_(d) (as per Test's constructor)
Test's constructor creates a new object which is the one that b in Test is ultimately set to?
Almost.
Test expects Bridge and there is a Bridge constructor which accepts Base and Derived publically inherits from Base. So a temporary object of type Bridge is created using d and this is used to construct t.
But this happens in main not in the Test constructor. Further this temporary object is destroyed at the end of the Test t(d); statement. However by this point you have copied the temporary object in your Test constructor so everything seems to be OK (apart from the memory leaks).
Suppose I have a class like the following:
class A { virtual ~A(); ... }
class B : public A { ... }
class C : public A { ... }
I also have a vector of unique_ptr which is declared this way:
std::vector<std::unique_ptr<A>> vec;
Assume vec is populated with unique_ptr to objects of derived class. What should I do if I want a deep copy of any of the vector elements, either b or c, and let a base class unique_ptr pointing to it? Originally I was doing things like
std::unique_ptr<A> tmp = std::make_unique<A>(*b);
I don't think this is correct.
One possible solution is to declare a virtual cloning method in the base class and override it for each subclass:
class A {
virtual ~A() {}
virtual std::unique_ptr<A> clone() const = 0;
}
class B : public A {
std::unique_ptr<A> clone() const override {
return std::unique_ptr<A>(new B(*this));
}
};
Edit:
An usage example:
void f(const A& original) {
std::unique_ptr<A> copy = original.clone();
// Here, copy points to an instance of class B.
}
I have a class B which has a member that is a pointer to an object of a A class. When using copy constructor on an object of type A, it is copied but the member variable is not.
Is there any way to copy an A object and to automatically make a copy of its B member?
The following code shows the problem I'm triying to explain:
class A
{
public:
A(char t_name)
{
name = t_name;
}
~A()
{
}
char name;
};
class B
{
public:
A* attribute;
B()
{
attribute = new A('1');
}
~B()
{}
};
int main()
{
B* b_variable = new B;
B* b_copy = new B(*b_variable);
return 0;
}
When using copy constructor on an object of type A, it is copied but the member variable is not.
Your code never calls any copy constructor in class A.
Your code calls a copy constructor in class B and it does exactly what is is supposed to, i.e. copies the value of attribute which is a pointer to a class A object.
In other words - after executing your code, you have two instances of class B and one class A instance. In the two class B instances attribute points to the same class A instance.
This is (most likely) not what you want.
As many already has pointed out (e.g. see #lostbard answer), you'll need a copy constructor in class B to do a deep-copy. A deep-copy is needed because class B have a pointer member.
Also you should do some clean up in class B destructor and in main.
#include <iostream>
using namespace std;
class A
{
public:
A(char t_name)
{
name = t_name;
}
~A()
{
}
char name;
};
class B
{
public:
A* attribute;
B()
{
attribute = new A('1');
}
/** Copy constructor */
B(const B ©)
{
// Make a new instance of class A
attribute = new A(*copy.attribute);
}
/** Assignment operator */
B& operator= (const B& other)
{
// Delete the existing class A instance
delete attribute;
// and create a new as a copy of other.attribute
attribute = new A(*other.attribute);
}
~B()
{
// Delete the class A instance
delete attribute;
}
};
int main()
{
B* b_variable = new B;
B* b_copy = new B(*b_variable);
// Delete the two class B instances
delete b_variable;
delete b_copy;
return 0;
}
There is no need for a copy constructor in class A. The default generated will do as Class A has no pointer members.
EDIT
As pointed out by #Slava you should always implement a assignment operator when you make a copy constructor (rule of three) so I added it to the code above.
Some like the rule of three to be the rule of five so it also include move. Read more here: https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
While there are many solutions, I'd bet sooner-or-later you'll end up with implementing the usual virtual a.clone();. That works flawless when you'll have derived classes of A (which is more-or-less the only legitimate reason why you're keeping A as a pointer to a heap-allocated object and not as a value member :) ).
Note that, when you're implementing clone() in your hierarchy, that C++ supports covariant pointer return types. Thus, if base has a virtual that returns e.g. Clonable*, then A's same method can return A* and A's descendant ADerived can return ADerived*. Feel free to understand 'can' as 'should' for the case of clone().
Create a copy constructor for A and for B:
class A
{
public:
A(char t_name)
{
name = t_name;
}
A(const A& copy)
{
name = copy.name;
}
~A()
{
}
char name;
};
class B
{
public:
A* attribute;
B()
{
attribute = new A('1');
}
B(const B ©)
{
attribute = new A(*copy.attribute);
}
~B()
{}
};
here's what I've got:
class A{
B* object;
const B& create_object(){
if(object == nullptr)
object = new B(this);
return *object;
}
}
Now, here's the thing. I am supposed not to allow creation of B in any other way than in A.
The only way I am allowed to create B objects is :
A a;
auto b1 = a.create_object();
Now as I am not supposed to allow the object creation I made all of B's constructors private and said that A is a friend of B.
HOWEVER when doing
auto b1 = a.create_object();
it doesnt compile as the copy constructor is called. Is there any way to avoid it? I don't want to return a pointer, it needs to be an object.
b1 will be deduced to B, not to const B&, so compiler will check, that copy-ctor is available, use const auto& for this case
A a;
const auto& b1 = a.create_object();
You can do what you want with a proxy object:
class source_of_B
{
class B &source;
source_of_B(B &source): source(source) {}
friend class A;
friend class B;
};
Because it has no public constructors, creation of such object is restricted to its friends. So you can add public constructor to B that accepts the proxy without compromising your requirement to create B's at controlled locations:
class B
{
int x;
B(int x): x(x) {}
friend class A;
public:
B(const source_of_B &arg): x(arg.source.x) {}
};
class A
{
B b;
public:
A(): b(5) {}
source_of_B create_object() { return source_of_B(b); }
};
int main()
{
A a;
B b = a.create_object();
}
but you can no longer use auto b = a.create_object(); with this method.
Edit
If your compiler supports return value optimization, which it probably does, you can go without the proxy. Just change create_object() to return B directly:
B create_object() { return b; }
auto b2 = a.create_object();
The copy constructor will be called by create_object() itself. The only problem would be that some (older) compilers have restrictions on the complexity of the function. See the Wikipedia article for example. Working example is at http://ideone.com/w1jKAd.