C++: Duplicating a tree of derived elements - c++

I have a base class and several derived classes. The base class looks like this:
class Base
{
int type; //the derived type the object belongs to
int nOfChildren;
Base** children; //each child can be any of the derived types
...
}
Now I need to duplicate an instance of Base. Because of the recursion, a virtual method Base::duplicate() is needed. It also seems clear what should go in it:
Base temp = new Base();
temp->type = temp;
temp->nOfChildren = nOfChildren;
temp->children = new Base*[nOfChildren];
beyond that, it's not so clear.
Do I allocate each temp->children[i] as a Base object or as a derived object? Do I need a case statement to cater to all possible derived types? Do I need to implement a duplicate() method for each derived type, even those that contain no other information than the Base class? (If a derived class contains more information, then it is clear that I need a separate mechanism. There are several derived classes that contain no further data than the base, although they contain different implementations of a handler() method not shown.)

You are right, a virtual method is needed for cloning the polymorphic object. OTOH, you can leverage C++ features to simplify writing it:
class Child : public ICloneable {
public:
// stuff...
Child *clone() const { return new Child(*this); }
}
Also, don't put collections of objects into arrays! Use std::vector instead.
class Base
{
// stuff...
std::vector<Base*> children;
}
Even better, use a smart pointer to wrap the cloning operation into an object std::vector will be able to manage transparently.
template<typename T>
struct clone_ptr {
T *object;
clone_ptr() : object(new T()) {}
clone_ptr(T *object_) : object(object_) {}
clone_ptr(clone_ptr<T> const &other) : object(other.object->clone()) {}
clone_ptr<T> &operator=(clone_ptr<T> other) {
std::swap(object, other.object);
return *this;
}
~clone_ptr() { delete object; }
};
That way you can just use a std::vector of clone_ptrs into your Base:
class Base
{
// stuff...
std::vector<clone_ptr<Base>> children;
}
Each object will be automagically copied into an object of the same polymorphic type, as long as you implement clone() in each class. The vector will be cloned in the same way other data members are, automatically by the C++ compiler.

Related

Access derived class's method covariant return, with derived constructed from factory with unique_ptr<AbstractBase>

Edit: My question might just be asking how to downcast a unique_ptr<base> to unique_ptr<derived> (which is already answered), but I am not 100% sure what I am asking
I have an Abstract Base Class Base
class Base{
public:
Base();
struct pStruct{};
virtual pStruct pFunc(std::vector<double> data) = 0;
protected:
CustomType dataValue;
};
and two derived classes Derived1 and Derived2 that implement Base
class Derived1 : public Base {
public:
struct pStructD1 : Base::pStruct {
CustomType data1;
std::vector<double> data2;
};
Derived1(uint32_t foo1, std::vector<double> foo2, ...);
virtual pStruct pFunc(std::vector<double> data) override;
private:
uint32_t bar1{0};
};
class Derived2 : public Base {
public:
struct pStructD2 : Base::pStruct {
int32_t data3;
std::vector<double> data4;
double data5
};
Derived2(std::vector<double> foo1, std::vector<double> foo2, ...);
virtual pStruct pFunc(std::vector<double> data) override;
private:
std::vector<double> bar2;
};
When calling class method pFunc(std::vector<double> data), each derived class will return different types, and amounts of values. I tried making this work with a covariant return type, so Derived1::predict(data).key1 might be a matrix, and .key2 might be something else, and so on. Derived2::predict(data).key1 might be the only key, and it could be a boolean. Each derived class defines their own ::predict() return fields, because they vary significantly.
The issue is, I construct these derived classes with a factory, that reads some of the input (construction is via ifstream), and figures out what derived class it should be, and then calls the corresponding factory.
class BaseFactory {
public:
static std::unique_ptr<Base> createObj(std::ifstream & file){
file.read((char *) specificTypeString, 2);//This isn't actually the code, just assume this part works
if(specificTypeString == "D2"){
return D2BaseFactory::createObj(file);
}
else if(specificTypeString == "D1"){
return D1BaseFactory::createObj(file);
}
else{
throw std::runtime_error("error");
}
}
};
With std::unique_ptr<Base> D1BaseFactory::createObj(std::ifstream & file); returning std::unique_ptr<Derived1>(new Derived1(param1, param2, ...)); and the same thing for `D2BaseFactory'.
Problem is, if I construct a Derived class with the common BaseFactory, and call pFunc() on the returned unique_ptr, it always will be the empty Base::pStruct == {} and thus trying to access members of the covariant pStructs isn't possible. I know this is because the factory createObj returns the base type, but is there any way to dynamically return the type I want so I can access the necessary fields in the derived pStructs? I think using raw pointers might work, but if possible i'd like to keep them as unique pointers.
You can do something similar to this:
class Base
{
public:
...
std::unique<pStruct> pFunc(...) { return DopFunc(); }
protected:
virtual std::unique<pStruct> DopFunc() = 0;
};
class Derived1 : public Base
{
public:
struct pStructD1 : Base::pStruct { ... };
// Used when calling the child factory directly...
std::unique_ptr<pStructD1> pFunc(...)
{
return std::make_unique<pStructD1>(...);
}
protected:
// Used when called through the Base factory...
std::unique<pStruct> DopFunc(...) override
{
// Call the other function for code sharing... (DRY)
return pFunc(...);
}
....
};
This could make sense if you used the derived class when you need the derived objects.
The real question is why you need to used the derived types... If it is for initialisation purpose, then maybe the factory should do it before returning the value.
If it is for some processing, then maybe you should have some virtual functions in pStruct. That way, you never need to know the derived type returned by the factory.
In some case, the visitor pattern might also be a solution.
If you need to always use the specific struct, then why not always use the specific factory too?
You can also cast the result but if you need to do it every time you create an object, it might make the code more complex that it need to be.
Alternatively, you could also have a template member function let say template <class T> std::unique_ptr<T> pFuncT(...) { ... }. That way, the client code can specified the desired type directly at construction. An empty object or an exception could be throw if the type is incorrect.

How to implement a class template that provides functionality to its derived classes to track their instances?

I am trying to create an abstract class template (InstanceTracker) that classes can inherit from if they need functionality to perform operations on all of their instances. The class holds a static vector of pointers to 'T', and every time an InstanceTracker constructor is run, I push back a new pointer to the vector. I do this through a purely virtual getDerivedPtr() method that returns 'T*', that every class that derives from InstanceTracker has to implement with return this;. You can probably already see what is wrong what this though. You can never call a purely virtual function from a base constructor - since it doesn't exist yet. How can I find a way around this problem for my InstanceTracker class? Here's the code for the class:
#pragma once
#include <vector>
template <typename T>
class InstanceTracker
{
public:
InstanceTracker() noexcept
{
allInstances_.push_back(getDerivedPtr());
}
InstanceTracker(const InstanceTracker& source) noexcept
: InstanceTracker()
{
}
InstanceTracker(const InstanceTracker&& source) noexcept
: InstanceTracker()
{
}
virtual ~InstanceTracker() noexcept
{
auto it = std::find(allInstances_.begin(), allInstances_.end(), this);
int index = it - allInstances_.begin();
allInstances_.erase(allInstances_.begin() + index);
}
virtual T* getDerivedPtr() = 0;
protected:
static std::vector<T*> allInstances_;
};
If you want to try to run the code and see why it doesn't work at the moment, here's a simple class that inherits from InstanceTracker:
class Derived1 : public InstanceTracker
{
public:
Derived1* getDerivedPtr() override
{
return this;
}
};
You'd probably be better off using composition rather than inheritance, but I'll assume you have have a good reason to prefer inheritance here.
The difficulty is that, when a base class constructor is run, the this pointer is a pointer to an instance of the base class only. The derived instance doesn't even exit yet. (Likewise, on destruction, the derived portion of the object has already been uninitialized). So if you call a virtual method, you'll get the base class implementation rather than the derived class's implementation. In your case, the base class implementation doesn't even exist, so you're stuck.
You can probably get away with casting the base class's this pointer to a pointer to the derived class, but that's not guaranteed to work and probably involves undefined behavior.
One way to solve this is to store pointers to the base type (InstanceTracker *) rather the pointers to the derived type. Then your getDerivedPtr method doesn't need to be virtual, and it can do the cast when it's safe.
template <typename T>
class InstanceTracker {
public:
InstanceTracker() noexcept {
allInstances_.push_back(this);
}
// other constructors elided for space
virtual ~InstanceTracker() noexcept {
std::erase(
std::remove(allInstances_.begin(), allInstances_.end(),
this),
allInstances.end());
}
T* getDerivedPtr() {
return static_cast<T*>(this); // downcast
}
protected:
// allInstances_ stores base class pointers
static std::vector<InstanceTracker*> allInstances_;
};
Notes:
If you use RTTI, run-time type identification, you can use dynamic_cast instead of static_cast. You should not use a reinterpret_cast because the compiler might need to adjust the base pointer as part of the cast.
You're likely to run into problems if you create an instance of a derived type as const.

how to allocate memory for specify type in polymorphism?

I have an abstract class that 3 other classes inherit from that and they are concrete classes. I have a pointer of type abstract class. I want to write a function, which receives an object of one of the 3 classes I mentioned, and then allocate memory for that (with base class pointer) and then assign the value of passed object to it. How can I new memory for that special type in my function?
(I don't know the type of the object I have received. I only know it inherits from my abstract class)
thanks.
The way I would solve this problem is that I would add a duplicate() method to the abstract base class, and I would implement it in each of the derived classes. Each implementation knows exactly how large it is, so it can use new to allocate the memory. It also knows exactly what content it has, so it can assign its value to the new instance. Nice, simple, elegant. and object-oriented.
There are two options for you.
Clone an object of the derived type.
Create a default-constructed object of the derived type.
Both of them can be implemented using virtual member functions.
You can see C++: Deep copying a Base class pointer on how to clone an object.
You can follow a similar path to return a default-constructed object.
struct base {
virtual ~base() {} // Remember to provide a virtual destructor
virtual base* make_new() const = 0;
};
struct derived : base {
virtual derived* make_new() const {
return new derived(); // Return a default-constructed object.
}
};
Add then call make_new() on the pointer.
The usual way of solving it is to add a clone member function that each class overrides. That can be a bit boiler-plate-ish however, so if you aren't afraid of templates you can automate the process:
#include <iostream>
#include <memory>
struct Abstract {
virtual ~Abstract() = default;
virtual std::unique_ptr<Abstract> clone() const = 0;
virtual void speak() const = 0;
};
template<class C>
struct Cloneable : Abstract {
std::unique_ptr<Abstract> clone() const override {
return std::make_unique<C>(*(C*)this);
}
};
struct Concrete : Cloneable<Concrete> {
void speak() const override {
std::cout << "Concrete";
}
};
void foo(Abstract& a) {
a.clone()->speak();
}
int main() {
Concrete c;
foo(c);
return 0;
}
Live Example
It works out of the box for copy-able classes. And if your class isn't copy-able, you can just override clone yourself, and do the thing that makes sense.

Abstract base class using template argument from derived class

I have a base class which provides pure virtual interfaces. I need this to store pointers to derived-class objects in a list of pointers to the base class.
The derived class is created using the template mechanism. The problem is now that if I want to have a virtual interface to return a type which is known only to the derived class, I need to pass it as a template argument as well. This is where the dilemma starts...
template <typename ITEM>
class base {
public:
virtual ITEM* get() = 0;
};
template <typename ITEM>
class derived : public base<ITEM>{
public:
ITEM* get() {...};
};
But when using a template in base I need to know this even when creating a list of base pointers:
base* myList[10] = {derived1, derived2,...}
Of course I don't know that type when I define my list. So I need to get rid of the template in my base class somehow.
EDIT: Got rid of this approach because it wasn't a useful approach at all. So no solution for this issue.
The code you write is not valid; there is not a single base type that is then parameterised like in Java, but a number of base<T> types. There is a way to obtain a wrapper for a truly generic object, and it is called "type erasure". It is used, for example in the implementation of boost::any.
Basically, you have a non-template base class with virtual functions, and then you make a template derived class that implements them. Note that the simplified version shown here does not work if you want to have an array of base objects, because base has pure virtual functions and thus cannot be instantiated (and because the T member of the derived type would be sliced off).
struct base;
template<typename T>
struct derived;
struct base {
virtual ~base();
// In this class we don't know about T, so we cannot use it
// Other operations that delegate to the derived class are possible, though
virtual std::size_t sizeofT() const = 0;
virtual const std::type_info& typeofT() const = 0;
// Since all you want is a pointer in "get", you could write it as a void*
virtual void* getPtr() = 0;
// Otherwise, we can implement this template function here that calls the virtual.
// Note that function templates cannot be virtual!
template<typename U>
U& getAs() {
// Verify that the type is the _same_ (no up/downcasts allowed)
// std::bad_cast is thrown here if U is not the same T used to build this object
derived<U>& meAsU = dynamic_cast<derived<U>&>(*this);
return meAsU.obj;
}
};
template<typename T>
struct derived : public base {
T obj;
// A couple of ctors to initialize the object, and the default copy/move ctors/op=
virtual ~derived();
derived(const T& o) : obj(o) {}
derived(T&& o) : obj(std::move(o)) {}
std::size_t sizeofT() const override {
return sizeof(T);
}
const std::type_info& typeofT() const override {
return typeid(T);
}
void* getPtr() override {
return static_cast<void*>(&obj);
}
};
If you want to use the base type directly as a variable, or in an array or container (vector, list, etc.), you need dynamic allocation - there are no two ways around it. You have two choices, which differ on where to place the responsibility for the dynamic allocation:
You can use the solution above if you limit yourself to having arrays of pointers to base. E.g. an array of std::unique_ptr<base>. The pointed-to objects would be of type derived<something>.
base err1; // Error, abstract class (what would it contain?)
base err2 = derived<int>(2); // Still abstract class, and the int would be sliced off
std::unique_ptr<base> ok(new derived<int>(3)); // Works
std::vector<std::unique_ptr<base>> objects;
objects.push_back(std::make_unique(new derived<int>(5)));
objects.push_back(std::make_unique(new derived<std::string>(2)));
int& a = objects[0].getAs<int>(); // works
std::string& b = objects[1].getAs<std::string>(); // works too
std::string& bad = objects[1].getAs<double>(); // exception thrown
Otherwise, you would have to implement the dynamic allocation in the base/derived classes themselves. This is what classes like boost::any or std::function do. The simplest any object would simply be a wrapper of an unique-ptr of the base class I showed here, with appropriate implementations of operators, etc. Then, you can have a variable of type any x = y; and the class would, inside its constructor, do the required new derived<Y>(y) required.

returning instance of derived class from base class member function

Is it an O.K. design if i return an instance of Derived class from Base class member function(created using new Derived()) ?
Also this involves the need to forward declare the Derived class and also make the Derived class constructor public.
Code Sample :-
Class Base
{
public:
Base() {}
Derived* get_new_derived(int X)
{
Derived *der = new Derived(X);
return der;
}
}
Class Derived : public Base
{
private:
int _X;
protected:
Derived(int X) { _X = X; }
public:
Derived* get_new_derived(int X)
{
Derived *der = new Derived(X);
return der;
}
}
I have one more derived class(say Derived1). Now let's say :-
Usage1 :
Derived1* der1 = new Derived1();
Derived * der = der1->get_new_derived(10);
Usage2 :
Derived1* der1 = new Derived1();
Base* bs = der1;
Derived * der = bs->get_new_derived(10);
In the general case, this usually indicates bad design - a base class shouldn't normally know/care about its derived classes.
Note that you can return a pointer to Derived typed as Base* - that's the principle of the Factory Method design pattern. Perhaps this fits your actual scenario?
Note however that all rules have exceptions. If your (base class + derived classes) represent a tighly coupled and coherent unit (such as a Tree interface with two subclasses FastTree and SmallTree, optimised for different purposes), it is acceptable for them to be aware of each other, and Tree defining such functions as:
std::unique_ptr<SmallTree> Tree::createSmallCopy() const
{
return { new SmallTree(/*args*/) };
}
std::unique_ptr<FastTree> Tree::createFastCopy() const
{
return { new FastTree(/*args*/) };
}
So it depends on your actual use case. I'd generally be wary of such design, it but it has its uses.
As a side note, in modern C++, you should never use an owning raw pointer - use a smart pointer like std::unique_ptr or boost::shared_ptr.
How about this?
// The Curiously Recurring Template Pattern (CRTP)
template<class Derived>
class Base
{
// methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
// ...
};
http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Yes you can do it. The question is whether you should.
You shouldn't do it since it implies Base knows Derived which isn't proper object oriented design. The dependencies should be one way - derived knows the Base and not vice versa.