-2

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!

linuxfever
  • 3,763
  • 2
  • 19
  • 43
  • 2
    You are looking for the [curiously recurring template pattern](http://stackoverflow.com/questions/4173254/what-is-the-curiously-recurring-template-pattern-crtp) – David Nehme Oct 20 '13 at 19:11
  • @DavidNehme: Thanks. However, it is important that I store derived objects in the same container. If I am not mistaken, using CRTP will remove that ability, no? – linuxfever Oct 20 '13 at 19:16
  • What is the problem with casting, as long as you are positive that you are passing in the right object? Or using dynamic_cast to make sure of that? – Tony Oct 20 '13 at 19:19
  • @Tony: If there is no alternative, I will use static_cast. But, ideally, I want to see first if there is a more 'elegant' solution to my problem. – linuxfever Oct 20 '13 at 19:25
  • If you know you have a `derived`, why are you pointing to it via a `base*`? – n. m. could be an AI Oct 23 '13 at 12:02
  • 1
    What does `allocate_memory_for_this();` do? (When the constructor is called, there's already an object..) Does `getNext` create a node in a singly-linked list, and you want to be able to create nodes inplace at some already allocated buffer? – dyp Oct 23 '13 at 13:48
  • 1
    That's so much suspicious code, I even can't start with an appropriate point what's wrong with it! Well, not worth a bounty at all .... – πάντα ῥεῖ Oct 23 '13 at 21:04
  • 2
    Tried to close vote because of _'minimal understanding'_ requirement, but that's denied due to open bounty :( ... – πάντα ῥεῖ Oct 23 '13 at 21:13
  • Suppose later you write "base *x=new Derived(); base *y=new Derived(); x->getNext_noAlloc(0,y);". What do you want to have happen? This is the scenario the compiler is worrying about. – dspeyer Oct 25 '13 at 21:44
  • @g-makulik: Good. That would be a very poor reason to close this question. You can't just close every question you don't like or don't understand, or wherein the OP doesn't already know his answer. – Lightness Races in Orbit Oct 30 '13 at 08:30

2 Answers2

2

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?

Community
  • 1
  • 1
Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
2

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

Community
  • 1
  • 1
Jed Schaaf
  • 1,045
  • 1
  • 10
  • 19
  • Could you please give an example using CRTP where I can hold derived objects in the same container? So, if I have `derived` and `derived`, how can I store these two in the same container? Thanks – linuxfever Oct 25 '13 at 08:45
  • Ah, ok. I get what you're trying to do. I'll update my answer. – Jed Schaaf Oct 30 '13 at 01:57