Search code examples
c++pointersdynamicdecoratorshared-ptr

Dynamic binding of shared_ptr


I'm trying to implement something following the decorator pattern, but I cannot seem to obtain from a shared_ptr the same run-time behaviour I can get through normal pointers. I have a basic class I (interface) with a virtual method, then I derive from it two classes:

  • class A (component) which will contain some data
  • class B (decorator) which derives from I and also contains a pointer to it and will implement some additional behaviour. I have a constructor that initialises the pointer to a certain I (or derived) object.

Then I want to be able to build a B object with its pointer pointing to an A, so that when I call the common methods I call the A ones not the I ones.

I can do this if I make the pointer in B in the usual way (in the code example, see the class B_basic and the object bb in the main).

But if I make this pointer like a shared_ptr to I it calls the method from I even if I build it pointing to an actual A (in code see the B_shared class and the object bs)

class I {

   public:
      virtual void method() {cout<<"I\n";}
      virtual ~I() = default;
};

class A : public I {
   public:
      virtual void method() {cout<<"A\n";}
};

class B_shared : public I {
   public:
      shared_ptr<I> shared_pointer;
      B_shared(const I& i) : shared_pointer(make_shared<I>(i)) {}
      virtual void method() { 
         cout<<"B_shared > ";

         shared_pointer->method();
      }
};

class B_basic : public I {
   public:
      I* basic_pointer;
      B_basic(I* i) : basic_pointer(i) {}
      virtual void method() { 
         cout<<"B_basic > ";

         basic_pointer->method();
      }
};


int main() { 
   A a;
   B_shared bs(a);
   B_basic bb(&a);
   bs.method(); // B_shared > I
   bb.method(); // B_basic > A
}

What am I doing wrong?


Solution

  • This is object slicing.

    In the following line you make a copy of the instance i of type A to type I. Thus the original type A is sliced to base type I.

    shared_pointer(make_shared<I>(i)) 
    

    In raw pointer version basic_pointer(i), you save the pointer itself, no slicing.