#include<iostream>
using namespace std;
class Something
{
public:
int j;
Something():j(20) {cout<<"Something initialized. j="<<j<<endl;}
};
class Base
{
private:
Base(const Base&) {}
public:
Base() {}
virtual Base *clone() { return new Base(*this); }
virtual void ID() { cout<<"BASE"<<endl; }
};
class Derived : public Base
{
private:
int id;
Something *s;
Derived(const Derived&) {}
public:
Derived():id(10) {cout<<"Called constructor and allocated id"<<endl;s=new Something();}
~Derived() {delete s;}
virtual Base *clone() { return new Derived(*this); }
virtual void ID() { cout<<"DERIVED id="<<id<<endl; }
void assignID(int i) {id=i;}
};
int main()
{
Base* b=new Derived();
b->ID();
Base* c=b->clone();
c->ID();
}//main
On running:
Called constructor and allocated id
Something initialized. j=20
DERIVED id=10
DERIVED id=0
My question is related to this, this and this post.
In the first link, Space_C0wb0y says
"Since the clone-method is a method of
the actual class of the object, it can
also create a deep-copy. It can access
all members of the class it belongs
to, so no problems there."
I don't understand how a deep copy can happen. In the program above, not even a shallow copy is happening. I need it to work even if the Base class is an abstract class. How can I do a deep copy here? Help please?
Well, your copy constructor does nothing, so your clone method does nothing in the way of copying.
See line Derived(const Derived&) {}
EDIT: if you add code to copy by assignment all members of Derived, it will become a shallow copy. If you also copy (by making a new instance) your instance of Something, it will become a deep copy.
Related
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).
I'm doing something called "deep copy", the clone() method requires to return a new instance of the derived class type using its copy constructor
Device.h
class Device : public Object{
public:
Device();
Device(const Device& copy);
~Device();
virtual Device* clone() = 0;
};
Radar.h
class Radar : public Device {
public:
Radar();
~Radar();
Radar(const Radar &Copy);
Device* clone();
};
Radar.cpp
Radar::Radar() {
}
Radar::Radar(const Radar& copy) {
}
Radar::~Radar() {
}
Device* Radar::clone() {
}
I have no idea how to deal with this method using copy constructor, anyone who can help me?
Note: You may want to consider using Radar* clone() override; in the derived class, which would allow an instance of the derived type to clone itself and maintain the same type (this is known as a covariant return type).
return a new instance of the derived class type using its copy constructor
return new Radar(*this);
new because you need a pointer to a new instance of the class
*this because the copy constructor signature is Radar(const Radar&)
A class with virtual functions usually has no copy constructor, because it usually does not make sense to copy objects of such classes. Allowing the copy constructor opens the door to all kinds of dangerous bugs related to slicing.
In other words (emphasis by me):
I'm doing something called "deep copy", the clone() method requires to
return a new instance of the derived class type using its copy
constructor
No, it does absolutely not require a copy constructor. It should prevent copying by deleting the copy constructor and the copy assignment operator.
Here is an example of how this should be done. Note that I've made the destructor virtual and that I've added some example members. I've also changed clone's signature to be const and used override to enable additional compilation checks.
class Device : public Object {
public:
Device() {}
Device(const Device&) = delete;
Device& operator=(const Device&) = delete;
virtual ~Device() {}
virtual Device* clone() const = 0;
};
class Radar : public Device {
public:
Radar(int i, const std::string& s) : i(i), s(s) {}
Radar* clone() const override
{
return new Radar(i, s);
}
private:
int i;
std::string s;
};
Depending on what your design requires, the Radar constructor invoked by clone could also be private.
Another thing is that you might want to consider a std::unique_ptr-based design:
class Device : public Object {
public:
Device() {}
Device(const Device&) = delete;
Device& operator=(const Device&) = delete;
virtual ~Device() {}
virtual std::unique_ptr<Device> clone() const = 0;
};
class Radar : public Device {
public:
Radar(int i, const std::string& s) : i(i), s(s) {}
std::unique_ptr<Device> clone() const override
{
return std::make_unique<Radar>(i, s);
}
private:
int i;
std::string s;
};
This is a recurrent problem once again. Someone know a easy way to do that? Imagine I have the following:
class Base
{
public:
...
Base property(const std::string& name)=0;
};
class Derived:public Base
{
public:
Derived();
Derived(const Derived&& val);
Base property(const std::string& name)
{
Derived z;
return z;
}
}
There is a way for the Derived::property return being (internally) a Derived copy instead of only Base part copy, and with the Derived move constructor invoked?
May be a stupid question, but really I dont find solution. Why copy constructors on return dont copy the specialized class?
Thanks you!
You can't do this.
Returning by value conceptually (ignoring RVO and move semantics) means making a copy of whatever you return by using the copy constructor of the type which the function is declared to return. If you return a Derived, a copy of type Base will be made and you'll lose the Derived part of the object. This is known as slicing.
If you want to return a Derived object as a Base, you'll need to use pointers.
The only aproximation I can find for who search something similar (related with X3liF, TartanLlama and other responses)
#define overridable(T) ovr<T>
#define return_overload_allowed(TYPE) friend struct ovr<TYPE>; virtual void* clone() const
#define return_overload_basic_allowed(TYPE) friend struct ovr<TYPE>; virtual void* clone() const{return new TYPE(*this);}
template<typename T> struct ovr
{
T* _obj;
ovr(const T& t)
: _obj(reinterpret_cast<T*>(t.clone()))
{;}
ovr(ovr<T>&& v)
: _obj(v._obj)
{
v._obj=nullptr;
}
operator T&()
{
return *_obj;
}
virtual ~ovr()
{
delete _obj;
}
};
class BASE
{
return_overload_basic_allowed(BASE);
public:
virtual overridable(BASE) method1();
virtual ~BASE();
};
class DERIVED: public BASE
{
return_overload_basic_allowed(DERIVED);
public:
virtual overridable(BASE) method1()
{
DERIVED a;
return a;
}
virtual ~DERIVED();
};
DERIVED a;
auto x = a.method1();
BASE& really_derived = x;
This compiles fine. But don't meet practical and smart requiriments... :(
This question already has answers here:
Copy constructor for a class with unique_ptr
(6 answers)
Closed 8 years ago.
When a class has a unique_ptr of a Base class what is a good way to implement the copy constructor.
Let me try to explain it with an example:
struct Base
{
virtual void doSth() = 0; // to make the class abstract.
};
struct Derived : public Base
{
virtual void doSth() override {}
};
struct Foo
{
std::unique_ptr<Base> bar;
Foo(const Foo& other) : bar(new Base(*other.bar)) // cant do it, its abstract.
{
bar = std::move(other.bar); // cant do it, reference object is modified.
}
};
Here as the class is abstract i cannot use its copy constructor. and also cannot use move on a constant reference ( we shouldnt do it actually, do not modify the object).
What I end up with is like so:
struct Base
{
virtual void doSth() = 0; // to make the class abstract.
};
struct Derived : public Base
{
virtual void doSth() override {}
Derived(const Base* b)
{
}
};
struct Foo
{
std::unique_ptr<Base> bar;
Foo(const Foo& other) : bar(new Derived(other.bar.get()))
{
}
};
However, it does not feel quite right, does it?
If you need to copy polymorphically, you will need to provide that in the interface of the type you are holding. Add a clone virtual function to Base and use that to create a copy that you can store in the copied Foo.
Other alternatives include not copying (delete the copy constructor) or use reference semantics (copies refer to the same object: change unique_ptr for shared_ptr) but neither of those alternatives really provide copies.
Here is the code for David's answer. Note that the virtual clone() is described in this answer.
#include <stdlib.h>
#include <cstddef>
#include <memory>
struct Base
{
virtual void doSth() = 0; // to make the class abstract.
virtual Base* clone() const = 0;
};
struct Derived : public Base
{
virtual void doSth() override {}
virtual Derived* clone() const {
return new Derived(*this);
}
};
struct Foo
{
std::unique_ptr<Base> bar;
Foo(const Foo& other) : bar(other.bar->clone()) // cant do it, its abstract.
{
}
};
I'm curious if in the following program Base* base in class Container can be replaced with Base& base?
With Base base it can't be replaced, because Base is abstract.
With Base& base the object should be allocated somewhere, so I still would not be able to get rid of the pointer to the allocated object.
#include <iostream>
class Base
{ public:
virtual void str()=0;
};
class A : public Base
{ int i;
public:
A(int i):i(i){}
void str(){std::cout<<i<<std::endl;}
};
class B : public Base
{ double f;
public:
B(double f):f(f){}
void str(){std::cout<<f<<std::endl;}
};
class Container
{ Base *base;
public:
Container(int i) { base=new A(i);}
Container(double f) { base=new B(f);}
void str(){ base->str();}
};
int main ()
{
Container c1(8),c2(13.0);
c1.str();
c2.str();
return 0;
}
With your code, I would't recommend it, because Container is the owner of base and a reference, semantically, means something else (an alias).
Technically, there's nothing stopping you:
class Container
{ Base &base;
public:
Container(int i) : base(*new A(i)) {}
Container(double f) : base(*new B(f)) {}
void str(){ base->str();}
};
Note that references have to be initialized in the initializer list.
You'd still need to clean up the memory, and it would look ugly with a reference:
~Container() { delete &base; }
instead of
~Container() { delete base; }
if you used pointers. Of course, using a std::unique_ptr instead of either of these two would make life a whole lot easier.
Also, be sure to implement (or declare as private or deleted) the copy constructor or assignment operator.
Later spot - You need to provide Base with a virtual destructor, otherwise you'll run into undefined behavior territory when you'll attempt to clean up the memory.