Hi all,

I have a problem with trying to call a protected base class function from an inherited class.

I have done some research and from what i can gather what i am trying to do is simply not permitted by the standard. The error i get when trying to compile is:

error: 'virtual void UIObject::onParentAttach(UIObject*)' is protected

The error is generated by:
virtual void SimplePanel::add( UIObject* pChild )

So what i am trying to achieve is that i have two functions in my base class virtual void UIObject::onParentAttach( UIObject* pParent ); virtual void UIObject::onParentOrphan() I want these to be used by container objects, and able to be reimplemented by other classes inheriting UIObject as necessary, but keep the functions out of the public API.

I can continue by making the UIObject functions public but thats not what i want, so i was hoping someone could throw some ideas out at how i can keep the functions out of public scope but still accessible by inheriting classes.

Thanks in advance :)

Stripped down source code follows:

//main.cpp

class UIObject
{
public:
   virtual ~UIObject() { }

   /* UIObject API */

protected:
   UIObject( UIObject* pParent )
   :
      m_pParent(pParent)
   {
   }

   virtual void onParentOrphan()
   {
      m_pParent = 0;
   }

   virtual void onParentAttach( UIObject* pParent )
   {
      m_pParent = pParent;
   }

   /* parent */
   UIObject* m_pParent;
};

class Panel : public UIObject
{
public:
   virtual ~Panel() { }

   /* panel methods */
   virtual void add( UIObject* pChild ) = 0;

protected:
   Panel()
   :
      UIObject(0)
   {
   }
};

class SimplePanel : public Panel
{
   SimplePanel() { }
   virtual ~SimplePanel() { }

   virtual void add( UIObject* pChild )
   {
      if( m_pChild )
      {
         m_pChild->onParentOrphan();
      }

      m_pChild = pChild;

      m_pChild->UIObject::onParentAttach( this );
   }

private:
   UIObject* m_pChild;
};

int main() {
    return 0;
}

As you say, there is a weird quirk about access to protected members. You can only call protected member functions on the "this" object, from a derived class. I don't know the reason behind this (if any), but it seems like a stupid rule to me.

In any case, you can circumvent the rule very easily, in many ways. This access rule applies only to calling protected non-static member functions, meaning that you can circumvent it by using anything else, like a protected data member, a protected nested class, or a protected static member function. Pick your poison.

Here are two options:

//main.cpp

#define USE_OPTION_1
//#define USE_OPTION_2

class UIObject
{
public:
   virtual ~UIObject() { }

   /* UIObject API */

protected:
   UIObject( UIObject* pParent )
   :
      m_pParent(pParent)
   {
   }

   virtual void onParentOrphan()
   {
      m_pParent = 0;
   }

   virtual void onParentAttach( UIObject* pParent )
   {
      m_pParent = pParent;
   }

#ifdef USE_OPTION_1
   struct ParentConnector {
      UIObject* m_pChild;
      ParentConnector(UIObject* pChild) : m_pChild(pChild) {};
      void makeOrphan() const {
         m_pChild->onParentOrphan();
      };
      void attachParent(UIObject* pParent) const {
         m_pChild->onParentAttach(pParent);
      };
   };
#endif

#ifdef USE_OPTION_2
   static void callOnParentOrphan( UIObject* pChild ) {
      pChild->onParentOrphan();
   };

   static void callOnParentAttach( UIObject* pChild, UIObject* pParent ) {
      pChild->onParentAttach(pParent);
   };
#endif

   /* parent */
   UIObject* m_pParent;
};

class Panel : public UIObject
{
public:
   virtual ~Panel() { }

   /* panel methods */
   virtual void add( UIObject* pChild ) = 0;

protected:
   Panel()
   :
      UIObject(0)
   {
   }
};

class SimplePanel : public Panel
{
   SimplePanel() { }
   virtual ~SimplePanel() { }

   virtual void add( UIObject* pChild )
   {

#ifdef USE_OPTION_1
      if( m_pChild )
      {
         UIObject::ParentConnector(m_pChild).makeOrphan();
      }

      m_pChild = pChild;

      UIObject::ParentConnector(m_pChild).attachParent( this );
#endif

#ifdef USE_OPTION_2
      if( m_pChild )
      {
         UIObject::callOnParentOrphan(m_pChild);
      }

      m_pChild = pChild;

      UIObject::callOnParentAttach(m_pChild, this );
#endif

   }

private:
   UIObject* m_pChild;
};

int main() {
    return 0;
}

Both options compile correctly and will result in no overhead at run-time since everything will be collapsed / inlined at the call site.

Edited 3 Years Ago by mike_2000_17: fix

This article has been dead for over six months. Start a new discussion instead.