2

I have two classes which resemble the following.

class Hand
{
public:
    func1();
    func2();
    ...
    func20();
private:
    Hand();
    ~Hand();
    Hand(const Hand& that);
    void operator=(Hand const&);
    friend class Body;
};

class Body
{
public:
    Body();
    ~Body();
    Hand * const &left_hand;
    Hand * const &right_hand;
private:
    Hand * _left_hand;
    Hand * _right_hand;
};

Body::Body()
:left_hand(_left_hand)
:right_hand(_right_hand)
{
    _left_hand = new Hand();
    _right_hand = new Hand();
};

This follows the Hand/Body relation. The hand belongs to the Body. -

  1. User cannot create/delete a Hand object.
  2. User cannot create a copy of the Hand object belonging to the Body.
  3. User cannot modify the left hand and right hand pointers of the Body object.

However, my colleagues say that to allow the user to directly call methods of a member object (in this case body->left_hand->func1()) is a bad design.

One suggestion was to use a getter funtion eg getLeftHand() which returns Hand * const instead of a read only public variable left_hand.

Another was to create wrapper functions for each Hand functions like

class Body
{
    Body();
    ~Body();
    leftHandfunc1();
    rightHandfunc1();
    leftHandfunc2();
    rightHandfunc2();
    ...
    leftHandfunc20();
    rightHandfunc20();
private:
    Hand * _left_hand;
    Hand * _right_hand;
};

And

Body::leftHandfunc1()
{
    _left_hand->func1();
}

However, as you can see, 20 methods of Hand equals 40 wrapper functions in Body. And this list is expected to grow. Should I go with this approach?

Is there any better alternative?

9
  • What about separate creation and interface of Hand by introducing an abstract base class (the interface)? Commented May 28, 2016 at 16:03
  • your class Body has only private memebrs and no public is that a typo? Commented May 28, 2016 at 16:07
  • 2
    If you want to just expose all the functionality of the hands through the interface of the body, just make the hands public members. Commented May 28, 2016 at 16:11
  • 1
    BTW, I would expose only Hand& not Hand*. Commented May 28, 2016 at 16:13
  • @BenjaminLindley . So calling body->left_hand->func1() in the application would be OK? Commented May 28, 2016 at 16:18

1 Answer 1

1

I would create an interface for Hand that exposes the publicly available functionality (only for read access):

struct IHand
{
public:
    virtual void func1() const = 0;
    virtual void func2() const = 0;
    ...
    virtual void func20() const = 0;
    virtual ~IHand() {}
};

class Hand : public IHand
{
public:
    void func1() const;
    void func2() const;
    ...
    void func20() const;
private:
    Hand();
    ~Hand();
    Hand(const Hand& that);
    void operator=(Hand const&);
    friend class Body;
};

In you Body class you can safely hand out const reference getters for _left_hand and _right_hand as follows:

class Body
{
public:
    Body();
    ~Body();
    const IHand& left_hand() const { return _left_hand; }
    const IHand& right_hand() const { return _right_hand; }
private:
    Hand _left_hand;
    Hand _right_hand;
};

Clients can access the interface like:

Body body;

body.left_hand().func1();
body.right_hand().func20();

This design would match for all your constraints:

  1. User cannot create/delete a Hand object.
  2. User cannot create a copy of the Hand object belonging to the Body.
  3. User cannot modify the left hand and right hand pointers of the Body object.

I wasn't sure about your last point, what is meant with modify. So I made everything const in the interface as a precaution.

Sign up to request clarification or add additional context in comments.

2 Comments

By point 3, I meant that body.left_hand = body.right_hand should not be possible. The earlier revision worked for me. I used pointers because the constructor of Hand needs to be called at the end of constructor of Body. I pass certain variables to the Hand constructor which are calculated in Body constructor. Likewise, need Hand to be destroyed before Body destructor begins. If this is possible with your current solution, that would be great.
@ShaunakGupte "Likewise, need Hand to be destroyed before Body destructor begins." It's already like this with my example code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.