Process Object Inheritance

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Process Object Inheritance

      I have created a class called DisplayManager which inherits from CProcess so I can attach it to the processManager.

      <code>
      CProcessManager ProcessManager;
      SmartPtr<CProcess> m_DisplayManager(new DisplayManager(hWnd));
      ProcessManager.Attach(m_DisplayManager);
      </code>
      Now this code compiles ok, except when I try to call a function of the derived class that does not exist in the base class.

      For example:
      m_DisplayManager->Init(hWnd, SCREEN_WIDTH, SCREEN_HEIGHT, FULLSCREEN);

      Getting the error message, CProcess::Init is not a member of CProcess.

      Please help me fix this issue.

      Thanks
    • RE: Process Object Inheritance

      Since your m_DisplayManager object is declared as a CProcess smart pointer - it knows nothing about the member functions of DisplayManager.

      Try this:

      SmartPtr<DisplayManager> m_DisplayManger(new ...);
      Mr.Mike
      Author, Programmer, Brewer, Patriot
    • Then attach the base class object:

      processManager.Attach(m_DisplayManager.get());
      Feel you safe and secure in the protection of your pants . . . but one day, one day there shall be a No Pants Day and that shall be the harbinger of your undoing . . .
    • Sorry, should have mentioned that I tried that,

      And I was getting this error:

      Error 1 error C2664: 'CProcessManager::Attach' : cannot convert parameter 1 from 'SmartPtr<T>' to 'SmartPtr<T>' c:\documents and settings\administrator\desktop\game developing\projects\customgui\customgui\winmain.cpp 111

      It looks the same to me. convert from SmartPtr<T> to SmartPtr<T>.

      Am I missing something?

      Thanks
      Chris Clark
    • Yeah, you are missing something, but it's kinda of a weird issue. The templated parameter in the SmartPtr<T> makes it a unique type. What you're doing is attempting to convert non-related templated types. Such as:

      Source Code

      1. typedef SmartPtr<int> IntPtr;
      2. typedef SmartPtr<float> FloatPtr;
      3. IntPtr foo(new int);
      4. FloatPtr bar = foo; //causes an error


      Although you know that there's a conversion from float to int, the compiler looks at the IntPtr and FloatPtr and sees two unrelated types (the pointer classes) and then throws an error.

      There're two ways to get around this.

      First: There should be an accessor in the SmartPtr class (such as is in boost::shared_ptr) that allows you access to the raw pointer. In the boost::shared_ptr, it's called get(). So, the way to convert related types, is to create a new pointer out of the raw memory:

      Source Code

      1. typedef SmartPtr<int> IntPtr;
      2. typedef SmartPtr<float> FloatPtr;
      3. IntPtr foo(new int);
      4. FloatPtr bar(foo.get()); //gets rid of the compiler error


      Now, there's a bug in this. You have two smart pointers pointing at the same memory. This means, when one or the other has no more references, the memory will be deleted, and all the other smart pointers will be pointing at bad memory.

      Second: The unique solution to your problem is one of casting. I solve your problem this way:

      Source Code

      1. CProcessManager ProcessManager;
      2. SmartPtr<CProcess> m_DisplayManager(new DisplayManager(hWnd));
      3. ProcessManager.Attach(m_DisplayManager);
      4. //.... whatever code goes here
      5. DisplayManager & disp_man = static_cast<DisplayManager>(*m_DisplayManager.get());
      6. disp_man.Init(/* whatever params here */);


      It seems kinda stupid to do this, but this is one of the problems with smart pointers.

      Thirdly: Another potential solution to your problem is the use of weak pointers. Check out Boost.WeakPtr for this one, but you could easily do something like this:

      Source Code

      1. CProcessManager ProcessManager;
      2. SmartPtr<CProcess> disp_man(new DisplayManager(hWnd));
      3. ProcessManager.Attach(disp_man);
      4. WeakPtr<DisplayManager> m_DisplayManager(disp_man.get());
      5. //.... whatever code goes here
      6. m_DisplayManager->Init();


      Note, weak pointers don't garuntee that the memory they're pointing to is valid. There is a function for checking if the pointer is still valid (in boost::weak_ptr) and there is also a function for getting a boost::shared_ptr of the same type if you need to create a shared_ptr out of a weak_ptr.

      Hope this helps.
      Feel you safe and secure in the protection of your pants . . . but one day, one day there shall be a No Pants Day and that shall be the harbinger of your undoing . . .

      The post was edited 1 time, last by Tarviathun ().

    • I have been getting a runtime error when using the following code:

      SmartPtr<DisplayManager> m_DisplayManager(new DisplayManager(hWnd));

      The m_DisplayManager variable contains nothing and when I check what happened, I am finding out that the runtime env called a vector deleting destructor. I don't know why this is happening.

      Please help.

      Thanks
    • Are you using boost::shared_ptr or your own implementation?
      Feel you safe and secure in the protection of your pants . . . but one day, one day there shall be a No Pants Day and that shall be the harbinger of your undoing . . .
    • I am using the implementation MrMike included in GCC edition 1.

      Included here:

      #ifndef SMARTPTR_H
      #define SMARTPTR_H

      #include <assert.h>
      #define NULL 0

      template <class T> class SmartPtr;

      //////////////////////////////////////////////////
      // IRefCount
      // is an interface for reference counting
      // Classes can implement it themselves,
      // or SmartPtr will provide its internal implementation of IRefCount

      template <class T> class IRefCount {
      friend class SmartPtr<T>;
      protected:
      virtual void AddRef() = 0;
      virtual void Release() = 0;
      virtual T * GetPtr() const = 0;
      };

      //=======================================================================================
      /////////////////////////////////////////////////
      // IRefCountImpl
      // is a standard implementation of IRefCount
      // To use it just derive your class from it:
      // class CMyObject : public IRefCountImpl<CMyObject> { ... };
      // Reminder: implementing IRefCount is optional but it would reduce
      // memory fragmentation

      template <class T> class IRefCountImpl
      : public IRefCount<T> //inherits from IRefCount and implements it
      {
      private:
      int m_Count;

      protected:
      virtual void AddRef() { m_Count++; } // adds one to the ref count
      virtual void Release() // decreases the ref count and destroys when the count reaches zero
      {
      assert(m_Count>=0);
      m_Count--;
      if(m_Count<=0)
      {
      Destroy();
      }
      }
      virtual T * GetPtr() const { return ((T *)this); } //returns the raw pointer
      virtual void Destroy() { if(GetPtr()!=NULL) delete GetPtr(); } // destroys the raw pointer

      IRefCountImpl() { m_Count = 0; } //constructor
      };

      //=======================================================================================

      //////////////////////////////////////////////////////////////
      // SmartPtr

      template <class T> class SmartPtr
      {
      private:
      IRefCount<T> *m_RefCount; //creates an instance of IRefCount

      ////////////////////////////////////////
      // RefCounter
      // An internal implementation of IRefCount
      // for classes that don't implement it
      // SmartPtr will automatically choose between its internal and
      // class' implementation of IRefCount
      class RefCounter : public IRefCountImpl<T> {
      private:
      T *m_Ptr;

      protected:
      virtual T * GetPtr() const { return m_Ptr; }
      virtual void Destroy() { delete this; }

      public:
      RefCounter(T *ptr) { m_Ptr = ptr; }
      virtual ~RefCounter() { IRefCountImpl<T>::Destroy(); }
      };

      // this method is called if T does not implement IRefCount
      void Assign(void *ptr)
      {
      if(ptr==NULL)
      Assign((IRefCount<T> *)NULL);
      else
      {
      Assign(new RefCounter(static_cast<T *>(ptr)));
      }
      }

      // this method is picked over Assign(void *ptr)
      // if T implements IRefCount.
      // This allows some memory usage optimization
      void Assign(IRefCount<T> *refcount) //called third
      {
      if(refcount!=NULL )
      refcount->AddRef();
      IRefCount<T> *oldref = m_RefCount;
      m_RefCount - refcount;
      if ( oldref != NULL )
      oldref->Release();
      }

      public:
      SmartPtr() { m_RefCount = NULL; }
      SmartPtr(T * ptr) { m_RefCount = NULL; Assign(ptr); } //called second
      SmartPtr(const SmartPtr &sp) { m_RefCount = NULL; Assign(sp.m_RefCount); }
      virtual ~SmartPtr() { Assign((IRefCount<T> *) NULL); }

      T *GetPtr() const { return (m_RefCount==NULL) ? NULL : m_RefCount->GetPtr(); } //called first

      // assignment operators
      SmartPtr& operator = (const SmartPtr &sp) { Assign(sp.m_RefCount); return *this;
      }
      SmartPtr& operator = (T * ptr) { Assign(ptr); return *this; }

      // T access and const conversion
      T * operator ->() { assert(GetPtr()!=NULL); return GetPtr(); }
      operator T* () const { return GetPtr(); }

      // utilities
      bool operator !() { return GetPtr()==NULL; }
      bool operator ==(const SmartPtr &sp) { return GetPtr()==sp.GetPtr(); }
      bool operator !=(const SmartPtr &sp) { return GetPtr()!=sp.GetPtr(); }

      };
      #endif