0

Let's say I have the following class hierarchy:

class A
{
public:
    virtual ~A();
};

class B : public A
{};

class AUser
{
public:
    virtual ~AUser();
protected:
    A* m_pA;
};

class BUser : public AUser
{};

Now I want to add a method to B which is not relevant for A and will be called only from BUser.

class B : public A
{
public:
    void addedFunctionality()
    {
        // do something
    }
};

To call the added method I have two options:

  1. Add an empty method to A:

    class A
    {
    public:
        virtual ~A();
        void addedFunctionality()
        {
            // do nothing
        }
    };
    
    class BUser : public AUser
    {
        void useB()
        {
            m_pA->addedFunctionality();
        }
    };
    
  2. call the added method using downcast:

    class BUser : public AUser
    {
        void useB()
        {
            static_cast<B*>(m_pA)->addedFunctionality();
        }
    };
    

I know downcasts should be avoided but I don't like the first option as it bloats A's code for no reason.

Is there any other design alternative?

Dvir Yitzchaki
  • 487
  • 4
  • 13
  • Can `BUser` also "be a" `B`? (i.e. `class B : virtual public A { void addedFunctionality(){} };` then `class BUser : virtual public AUser, virtual public B` ..? – txtechhelp Feb 03 '15 at 06:28
  • no, `BUser` is just a user, not a service. – Dvir Yitzchaki Feb 03 '15 at 06:30
  • 1
    For one, unless you know that you have a `B`, you should use `dynamic_cast` instead of `static_cast`. However, if you know it, you could as well store a pointer to `B` instead to begin with. Further, you might be able to use the Visitor Pattern. Other than that, it's hard to suggest things without really knowing what's going on. – Ulrich Eckhardt Feb 03 '15 at 06:37

1 Answers1

0

The simplest solution looks like this (also suggested by Ulrich Eckhardt):

class AUser
{
public:
    AUser(A* a)
    {
      m_pA = a;
    }
protected:
    A* m_pA;
};

class BUser : public AUser
{
public:
    BUser(B* b) : AUser(b)
    {
      m_pB = b;
    }

    void useB()
    {
        m_pB->addedFunctionality();
    }
protected:
    B* m_pB;
};

Less clean, but you may also consider this:

class BUser : public AUser
{
public:
    BUser(B* b) : AUser(b)
    {
    }
    void useB()
    {
        getB()->addedFunctionality();
    }
protected:
    B *getB()
    {
      return dynamic_cast<B*>(m_pA);
    }

};
Community
  • 1
  • 1
Gábor Angyal
  • 2,225
  • 17
  • 27
  • With the first option, maybe it's better to simply hide the base pointer with: `class BUser : public AUser {protected: B* m_pA};`, no? – Dvir Yitzchaki Feb 03 '15 at 10:34
  • 1
    Or you can simply make it private. – Gábor Angyal Feb 03 '15 at 11:10
  • When there's no reason for the derived class to access the base class' pointer, then private is the way to go. This applies to both AUser and BUser, btw. In addition, it can (and should!) be initialized in the initializer list, which would even allow making it constant. Also a fine detail in the second version: The dynamic_cast may not be necessary (I'd add it in an assertion though) because the constructor and remaining code can guarantee that only Bs are stored there. – Ulrich Eckhardt Feb 04 '15 at 19:14
  • If `m_pA` is not constant, then does using the initializer list really make a difference? – Gábor Angyal Feb 04 '15 at 19:18