Reputation: 65
I have 4 classes: 1 Base
, 2 Derived
s and 1 Container
class.
The Container
class holds a vector of Base
pointers.
I want to create a copy constructor for my class Container
that doesn't cast the Derived
pointers to a Base
, so that I can cast the Base
pointers to Derived
pointers afterwards.
class Base {
int m_base_attribute;
public:
Base() : m_base_attribute(420) {}
virtual void say_hello() {
std::cout << "Hello !" << std::endl;
}
};
class Derived : public Base {
int m_derived_attribute;
public:
Derived() : Base(), m_derived_attribute(69) {}
virtual void say_hello() {
std::cout << "I'm a derived class !" << std::endl;
}
};
class Container {
std::vector<Base*> m_base_vector;
public:
Container() {
m_base_vector.push_back(new Derived());
}
Container(const Container& model) {
for(auto base : model.m_base_vector){
m_base_vector.push_back(new Base(*base));
}
}
~Container() {
for(auto base : m_base_vector) {
delete base;
}
}
};
Is there a way to do it without any memory leaks?
Upvotes: 0
Views: 77
Reputation: 20579
The problem is that new Base(*base)
always creates a Base
object, never a Derived
object. This is called slicing. The workaround is to use a virtual clone
function and a virtual destructor:
class Base {
int m_base_attribute;
public:
// ...
virtual std::unique_ptr<Base> clone() const
{
return std::make_unique<Base>(*this);
}
virtual ~Base() {}
};
class Derived : public Base {
int m_derived_attribute;
public:
// ...
std::unique_ptr<Base> clone() const override
{
return std::make_unique<Derived>(*this);
}
};
Note that I used std::unique_ptr
instead of raw pointers to avoid memory leaks. Now you can implement the Container
class without slicing:
class Container {
std::vector<std::unique_ptr<Base>> m_base_vector;
public:
// ...
Container(const Container& model)
{
m_base_vector.reserve(model.m_base_vector.size());
for (const auto& p : m_base_vector) {
m_base_vector.push_back(p->clone());
}
}
};
Upvotes: 2