Question

I have a template class which is constructed by taking two arguments, an integer and a previous instance of that class. I want to be able to store instances of those classes in containers, which is why I have it inheriting from a base class (please ignore the non-smart pointers):

class base {
  virtual base* getNext(unsigned x) = 0;
};

template <class D>
class derived :
  public base {

  /* no memory allocation here, simply changes the data in next */
  void construct_impl(unsigned x, const derived<D>& previous, derived<D>& next); 


  derived();            /* default constructor */

  derived(unsigned x, const derived<D>& previous) { /* construct from previous object */
    allocate_memory_for_this();
    construct_impl(x, previous, *this);
  }

  base* getNext(unsigned x) {
    return new derived(x, *this);
  }
};

Now I would like to create a function in the base class which will construct an object of derived<D> in the same way as construct_impl does, ie without allocating memory anew. I was thinking something like this

class base {
  virtual base* getNext(unsigned x) = 0;
  virtual void  getNext_noalloc(unsigned x, base* already_allocated_derived_object) = 0;
}

which will be overriden in the derived class like this

void getNext_noalloc(unsigned x, base* already_allocated_derived_object) {
     construct_impl(x, *this, *already_allocated_derived_object);    
}

which unfortunately does not compile since there is no conversion from base* to derived<D>* (unless I use a static_cast). Is there any way to achieve what I need? Thanks in advance!

Was it helpful?

Solution

The curiously recurring template pattern that David Nehme linked to in the comments might do what you're looking for. It shouldn't keep you from storing objects of the derived class together in the same container. It does look like you're implementing a doubly-linked list with automatic creation of the next item from a given one. (This would invalidate the list from that element to the end unless it is the tail.)

I believe (I haven't tried it yet) you should test a dynamic_cast<> in the overrides for getNext_noalloc() to test the next pointer and call the matching class's construct_impl().

// override in derived class
void getNext_noalloc(unsigned x, base* already_allocated_derived_object) {
  derived<D1>* p1 = dynamic_cast< derived<D1> >(already_allocated_derived_object);
  derived<D2>* p2 = dynamic_cast< derived<D2> >(already_allocated_derived_object);  
  if(p1 != NULL) {
    p1->construct_impl(x, *this, *p1); // 2nd parameter should take base type
  } else if(p2 != NULL) {
    p2->construct_impl(x, *this, *p2); // 2nd parameter should take base type
  }
}

This does assume that the two classes know about each other, so you have to have the function definitions after the classes have been declared, and if construct_impl() is private or protected, the classes will have to be friends.

Using dynamic_cast<>() should mean you don't need the CRTP after all, but you will have to check each cast to ensure it converts to the correct type.

Casting pointers from base type to child type

OTHER TIPS

You may be laboring under the misapprehension that it's possible in C++ to write

class ClownCar {
    unsigned int x;
    ClownCar inner_car;
};

But this is impossible! What would sizeof(ClownCar) be? It would have to be at least sizeof x + sizeof inner_car; i.e., sizeof(unsigned int) + sizeof(ClownCar); i.e., at least four bytes bigger than itself.

So, a class can't contain an instance of its own class. Inheritance, virtual or otherwise, is irrelevant here. So what do we do? We use pointers!

class ClownCar {
    unsigned int x;
    ClownCar *inner_car;
public:
    ClownCar() : x(0), inner_car(nullptr) {}
    ClownCar(unsigned int x, ClownCar *previous) : x(x), inner_car(previous) {}

    ClownCar *getNext(unsigned int x) {
        return new ClownCar(x, this);
    }
};

int main() {
    ClownCar inmost_car;
    ClownCar *car1 = inmost_car.getNext(42);
    ClownCar *car2 = car1.getNext(43);
    // ...
    delete car2;
    delete car1;
    // of course we don't delete inmost_car, since it lives on the stack
}

Of course this isn't very C++ish. We probably want to get rid of all these *s, and also make it so that each car "takes ownership" of its inner car (and takes responsibility for deleting it, too). We can do this using the Standard Library's std::unique_ptr to represent this concept of "ownership" (see also How do I pass a unique_ptr argument to a constructor or a function?)... but really, all we've got here is a singly-linked list of ClownCars, and that's something that the STL gives us for free:

struct ClownCar { unsigned int x; };
typedef std::list<ClownCar> ClownCarList;  // ta-da!

So I think the real question is, what are you trying to accomplish?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top