Djay
Djay

Reputation: 23

How to copy polymorphic object

The function "foo" is from external library (In my case DEAlII ). It takes in class type as template parameter and its object. It then creates a copy of this object and performs some operation on this object.

The problem is when the input class is polymorphic (template ). Then I always pass base class object but pointing to different derived class, but the copied object in the function "foo" will be base class. And any call to member function on this copied object will call base class member function(But I need them to call to corresponding derived class member function).

Additionally the type of derived class is decided at runtime based on some input parameter. I cannot change/ move to different library, but I should be able to modify the function "foo" in the library(preferably not but may be as a last resort).

#include <iostream> 
#include <memory>
using namespace std;
class Shape {
   protected:
      int width, height;

   public:
      Shape( int a = 0, int b = 0){
         width = a;
         height = b;
      }

      void set(int a){
          width =a ;
      }

      virtual int area() {
         cout << "Parent class area :" <<endl;
         return 0;
      }
      virtual ~Shape()=default;
};
class Rectangle: public Shape {
   public:
      Rectangle( int a = 0, int b = 0):Shape(a, b) { }

      int area () override{ 
         cout << "Rectangle class area :" <<width*height <<endl;
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      Triangle( int a = 0, int b = 0):Shape(a, b) { }

      int area () { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
      Triangle(const Triangle &triangle){
          width = triangle.width;
          height = triangle.height;
      }
};

template <class temp>
void foo (temp &shape){
  shape.area();
  temp shape_sample = shape;
  shape_sample.area();
}
// Main function for the program
int main() {
    unique_ptr<Shape> shape;
    Rectangle rec(10,7);

   shape =make_unique<Rectangle> (rec);

   foo (*shape.get());
   shape->area(); 
   return 0;
}

Upvotes: 2

Views: 334

Answers (2)

milad lashini
milad lashini

Reputation: 125

If the implementation of the foo could not be changed. one other option is to write a wrapper around it and using dynamic cast send the right type to it.

    template <class temp>
    void foo (temp &shape)
    {
      shape.area();
      temp shape_sample = shape;
      shape_sample.area();
    }

    void fooWrapper(Shape* shape)
    {
        Rectangle* shape1 = dynamic_cast<Rectangle*>(shape);
        if (shape1)
        {
            foo<Rectangle>(*shape1);
            return;
        }
        Triangle* shape2 = dynamic_cast<Triangle*>(shape);
        if(shape2)
        {
            foo<Triangle>(*shape2);
            return;
        }

        shape->area();
        return;
    }
    // Main function for the program
    int main() {
        unique_ptr<Shape> shape;
        Triangle tri(10,7);

       shape =make_unique<Triangle> (tri);

       fooWrapper(shape.get());
       Rectangle rec(10,7);

       shape = make_unique<Rectangle> (rec);
       fooWrapper(shape.get());

       return 0;

}`

Upvotes: 0

r3mus n0x
r3mus n0x

Reputation: 6144

If the implementation of foo can't be change then I see two options here:

Option 1: Simply downcast to appropriate type if you know what it is:

foo(static_cast<Rectangle &>(*shape.get()));

Option 2 (overkill): hide the polymorphism using Bridge pattern:

class Shape {
protected:
    class ShapeImpl {
    public:
        int width, height;
        virtual ~ShapeImpl() = default;

        // "virtual copy constructor" which you could've used without a Bridge
        // if you could change "foo"
        virtual ShapeImpl *clone() { return new ShapeImpl(*this); }

        virtual int area() {
            cout << "Parent class area :" <<endl;
            return 0;
        }
    } *impl; // can't use unique_ptr because we want copy

    Shape(ShapeImpl *impl)
        : impl(impl) { }

public:
    Shape(const Shape &other)
        : impl(other.impl ? other.impl->clone() : nullptr) {
    }
    Shape(Shape &&other)
        : impl(nullptr) {
        std::swap(impl, other.impl);
    }
    virtual ~Shape() {
        delete impl;
    }
    // copy-and-swap idiom with one assignment operator to "rule-of-five them all"
    Shape &operator=(Shape other) {
        std::swap(impl, other.impl);
        return *this;
    }
    int area() {
       return impl->area();
    }
};

class Rectangle : public Shape {
protected:
    class RectangleImpl : public ShapeImpl {
    public:
        ShapeImpl *clone() override { return new RectangleImpl(*this); }
        int area() override {
            cout << "Rectangle class area :" <<width*height <<endl;
            return (width * height);
        }
    };
public:
    Rectangle(int width = 0, int height = 0)
       : Shape(new RectangleImpl())
    {
        impl->width = width;
        impl->height = height;
    }
};

Upvotes: 1

Related Questions