2

This is already several posts that I sent about this subjet and I apologize if this bothers some of you. After playing around several days and trying different alternatives (patterns) I came up with the following conclusions, which allows me to better formulate my question.

I have a vector of Base * and there are various Derived<T> classes that derive from Base. The different class parameters T are declared at the beginning with a forward declaration. What I need is to take a pair of objects from this vector<Base *> and apply a function(Derived<T1> obj1, Derived<T2> obj2) using templates in order to do some kind of double dispatch. However, I am unable to convert a pointer-to-Base to a pointer-to-Derived when I take an element from the vector. Thus, I cannot use function(Derived<T1> obj1, Derived<T2> obj2).

Of course, this could be simply achieved using dynamic_cast<Derived<T> *>(base_ptr). However, this is not what I want since to do this, one must know T in advance, which is not the case here. I must be able to select whatever elements from the vector, without knowing their Derived<T> type.

Therefore, I tried polymorphic cloning. Although it uses covariant return types, unfortunately, it did not work. The reason, as explained by different people in SO, and according to the C++ standard, is that at compile time, the compiler still does not know the complete type of the object. Thus, although one expects that the clone() should return a Derived<T> *, it returns a Base *.

The few next lines of code express what I mean. In general, the polymorphic cloning is used in the following case:

Base *b1 = new Derived;
Base *b2;
b2 = b1->clone();

This is not what I want. What I need is a pointer-to-Derived:

Base *b1 = new Derived;
Derived *d1;
d1 = b1->clone(); // This is what I want, but it fails.

Here, the compiler complains saying that an object of type Base * cannot be assigned to an object of type Derived *. Hence, I cannot use *d1 in function(,).

I also tried the non-virtual interface (NVI) method, but it did not work.

Does anyone have an idea of how to solve the simple code above, in particular, the last line ? Many thanks in advance.

2 Answers2

3

What you want is not possible, since there is no guarantee that the object pointed to by a Base * is actually an instance of Derived.

The most you can do is to use covariant return types for your clone() function.

class Base
{
public:
    virtual Base* clone() const
    {
        return new Base(*this);
    };
    virtual ~Base() {};
};

class Derived : public Base
{
public:
    virtual Derived* clone() const    // note different return type
                                      // this does override the inherited version
    {
        return new Derived(*this);
    }
};


int main()
{
    Base *b = new Derived;
    Derived *d1 = b->clone();    // this does not work

    Derived *o = new Derived;
    Derived *d = o->clone();    // this works
}

If you want to clone from a Base * to a Derived *, it is necessary to do a runtime check and force a type conversion.

Base *b = new Derived;

Base *temp = b->clone();
Derived *d = dynamic_cast<Derived *>(temp);
if (d)
{
     // d is actually an instance of Derived so can be used as such
}
else
{
     //  The cloning did not produce a Derived.  Cope with it
}
delete temp;   // this will delete the object pointed to by d, since it is the same object

Generally, however, what you are asking is a positive indicator of a flawed design. In general terms (assuming you need a class hierarchy with a polymorphic base) you need to design the Base so its interface (particularly set of virtual functions, which may be specialised by derived classes) are sufficient for all users of the class to do what they need. All users of Base should need is a pointer or reference to Base (i.e. a Base & or a Base *), and there should be no need for them to cast from Base to Derived. Look up "Liskov Substitution Principle" for more information.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • Thanks for your answer. Indeed a dynamic_cast would solve the problem in two lines, without even using clone(). However, I have different `Derived` and if I use dynamic_cast, I will have to use some if-else, as you do in your code, which I want to avoid. Moreover, the class parameters T, are not known in advance, they are defined at the very beginning by the user with a forward declaration. Therefore, one would have to change the code (the if-else) each time different T are defined. I am looking for some automated method such as the clone(). – Christophe J. Ortiz Sep 09 '15 at 10:07
  • @Peter If you're going to delete a derived object through a `Base` pointer, then Base's destructor must be virtual. – eerorika Sep 09 '15 at 10:16
  • @ChristopheJ.Ortiz if you don't know at runtime that a `Base*` points to a `Derived` but want to get a `Derived*`, then there is simply no way to avoid an if-else check. There is a construct in c++ that can easily solve a changing class parameter at compile time without changing code. It's a template. – eerorika Sep 09 '15 at 10:23
  • @Chris - what you're asking for is actually a sign of a broken design. For user: yes, a virtual destructor is needed. I've updated my post in response to both. – Peter Sep 09 '15 at 10:25
0

I think in this case you should do casting. You could google more about static_Cast and reinterpret_cast. Here's some references : How to force implicit conversion in polymorphism, Proper way of casting pointer types

Community
  • 1
  • 1
Nguyen Quang Anh
  • 315
  • 1
  • 3
  • 12
  • The problem could be solved with a dynamic_cast, indeed. But this is not what I want since one must know in advance the type (Derived) to do `dynamic_cast *>`, as explained in my post. If I take randomly two elements from my `vector`, a priori they will be of type `Derived` and of type `Derived`, which I do not know. Thus, if I do a dynamic_cast, I'll have to do some if-else to check if the conversion was ok, which I want to avoid. – Christophe J. Ortiz Sep 09 '15 at 10:11