1

Say I have a class Face. I wish to use composition to build Face. Face has eyes, so I can create a class Eyes and use composition adding eyes to Face.

But what if I subclass eyes, e.g.

class Eyes { ... };
class BlueEyes : public Eyes { ... };
class BrownEyes : public Eyes { ... };

? (Assume interfaces are all identical.)

Is it possible to compose Face at run-time, say depending on some parameter provided to the constructor a Face would get either BlueEyes or BrownEyes?

PartialOrder
  • 2,870
  • 3
  • 36
  • 44
  • That's exactly why there is object composition as opposed to inheritance? – iksemyonov Feb 13 '16 at 13:47
  • 4
    `Face` should have a member of type `std::unique_ptr` and at run time you create the correct desired type, e.g. `colour == Eyes::Brown ? new BrownEyes : new BlueEyes` and manage that pointer in the `unique_ptr` member. (Make sure `Eyes` has a virtual destructor). – Jonathan Wakely Feb 13 '16 at 13:53

2 Answers2

4

You can do this by composing a pointer to the base class. E.g.,

enum EyeColor{Blue, Brown}; // Even better would be enum class

class Face
{
private:
    // Here is the composition - to a base-class ptr.
    std::unique_ptr<Eyes> m_eyes;

public:
    explicit Face(EyeColor c) 
    {
        // Use c to instantiate m_eyes below to the appropriate-class object.
    }
};

In fact, the C++ implementation of some design patterns, e.g., Strategy, often employ this.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
0

What you are looking for is the factory design pattern.

Your factory receives the name of the class to instantiate, and any required parameters, then instantiates the appropriate subclass. The name could take the form of a string, an enumerated type, or any other means of selecting the appropriate subclass. Let's use a string:

Eyes *create_eyes(const std::string &color)
{
   if (color == "blue")
          return new BlueEyes;

   if (color == "brown")
          return new BrownEyes;

   throw "Unknown eye color";
}
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • 3
    This should be returning `unique_ptr`, or if you're stuck in the past, `auto_ptr` – Jonathan Wakely Feb 13 '16 at 13:56
  • 1
    Smart programmers, who want exception-safe and bug-free code. Raw pointers have few advantages, *particularly* as return values and class members. – Cody Gray - on strike Feb 14 '16 at 13:36
  • The right tool, for the right job. The question here is to give an example of a factory, not to discuss the pros and cons of smart pointers. – Sam Varshavchik Feb 14 '16 at 14:41
  • A raw pointer is not the right tool for the job of indicating that the caller owns the pointer returned by the factory. – Jonathan Wakely Feb 14 '16 at 16:55
  • The question here was not about properly designing and defining ownership of heap-allocated objects, but a general question about the appropriate design factory for the given situation, and this was nothing but the simplest example possible. I am not certain that the OP was even knowledgeable in the intricacies of reference-counted objects; and this would've probably added to the confusion, with little to benefit from it, in exchange. – Sam Varshavchik Feb 14 '16 at 17:46