Lorin
Lorin

Reputation: 341

CPP: Class as private member in another class

For example, I create a Button class. Button should have its own text (with color, size, font, spacing, etc.), states and background.

Because text labels are useful even in another widgets (text labels, text edits, etc.) I put all needed in another class (call it Label).

Background color is useful too, so I created another class - Color with all needed methods - changing, comparing...

Now come back to Button class.

class Button {
    private:
        Color _bgColor;
        Label _text;

        /* another private members */

    public:
        /* Content of Button class */
};

But what if I would like to change the button background color? In this case, I need to write another two methods => setColor and getColor. In fact, I have to write all methods which are defined for Color class.

Another option is to define private classes as public and access them like button.bgColor.setColor(). But it seems weird to me to one time call button.disable and another time button.color.setColor.

Is there any other option which I don't know about? Thank you for help.

Upvotes: 0

Views: 515

Answers (3)

Chad
Chad

Reputation: 19032

You're correct in that when something has attributes those attributes need to be exposed somehow, and that can lead to code bloat. However, as with all things a simple layer of abstraction can make things easier.

You can provide "helper classes" for these types of attributes and use them as mixins. This will keep the code as small as possible while still

class HasLabel
{
public:
   void SetLabelText(const std::string& text);
   const std::string& GetLabelText() const;

private:
   Label label_;
};

class HasBackgroundColor
{
public:
   void SetBackgroundColor(const Color& color);
   const Color& GetBackgroundColor() const;

private:
   Color color_;
};

class Button : private HasBackgroundColor, private HasLabel
{
public:
   // Expose BkColor
   using HasBackgroundColor::SetLabelText;
   using HasBackgroundColor::GetLabelText;

   // Expose Label
   using HasLabel::SetLabelText;
   using HasLabel::GetLabelText;
};

You could also use public inheritance and then the using directives wouldn't be necessary, but whether that's acceptable (if a Button truly "is-a" HasLabel) is a matter of personal preference.

You could also use the CRTP to reduce the amount of boilerplate code for objects with similar mixins.

Upvotes: 1

haansn08
haansn08

Reputation: 157

But what if I would like to change the button background color? In this case, I need to write another two methods => setColor and getColor. In fact, I have to write all methods which are defined for Color class.

Why would you do that? Just define a function SetBackgroundColor(Color &newColor) for setting the color and const Color& GetBackgroundColor() const for accessing it!

Upvotes: 1

japreiss
japreiss

Reputation: 11251

But what if I would like to change the button background color? In this case, I need to write another two methods => setColor and getColor. In fact, I have to write all methods which are defined for Color class.

Not true. You only need to write those two methods. Anything else just happens through the getColor return value. For example, to test if two buttons have the same color, you'd write:

if (button1.getColor() == button2.getColor())

not

if (button1.hasSameColor(button2))

That is, unless you want to hide Button's use of the Color class as an "implementation detail." I wouldn't recommend that. Programs dealing with color should usually treat colors as a value type, akin to plain numbers, points, vectors, etc.

Upvotes: 0

Related Questions