I am designing a project in C ++ and have come to a point that I doubt, whereas I should use inheritance only for polymorphism.
In particular, I have a class JazzQuartetthat has 4 properties: Saxophonist, Pianist, Bassistand Drummer, each of which has methods play()and listen()with different implementations.
JazzQuartet
Saxophonist
Pianist
Bassist
Drummer
play()
listen()
I would like to make them all inherited from class Musician, so I can have an array of objects Musicianand invoke methods play(), and listen()each of them as well as I do any Musician listen()other age groups. But since their implementation is completely different from each other, I would use this legacy to get polymorphism, and I'm not sure if this is a good design choice.
Musician
Any advice on this?
Thank you all in advance!
"... so I can have an array of Musician objects and call the methods of each of them () and listen (), and I can also force any musician to listen () for any other."
Musician should be an abstract class, i.e. an interface:
class Musician { public: virtual void play() = 0; virtual void listen(Musician& other) = 0; virtual bool isPlaying() = 0; virtual ~Musician() {} };
And yes, he believed that good design favors interfaces.
This way you ensure that these derived classes perform these functions and allow clients to access instances Musicianwithout requiring a specific derived type to be known.
As you asked to save the entire ensemble to an array:
In the above design, you can use an array std::unique_ptr<Musician>to combine a specific ensemble of musicians.
std::unique_ptr<Musician>
std::vector<std::unique_ptr<Musician>> jazzQuartet(4); std::unique_ptr<Saxophonist> sax = new Saxophonist(); std::unique_ptr<Pianist> piano = new Pianist(); std::unique_ptr<Bassist> bass = new Bassist(); std::unique_ptr<Drummer> drums = new Drummer(); jazzQuartet[0] = sax; jazzQuartet[1] = piano; jazzQuartet[2] = bass; jazzQuartet[3] = drums; // And wire them up as necessary //------------------------------------ // Usually everyone in the combo needs to listen to the drums sax->listen(*drums); piano->listen(*drums); bass->listen(*drums); ... // Let them all play for(auto& m : jazzQuartet) { // Note the & to avoid copies made for the items m->play(); }
, Musician . , Pure Abstract Class. , .
, , , , , , , , Musician , , , .
"" , , Musician.
, , , - (, -/?).
. Saxophonist, Pianist, Bassist Drummer "Is-a" Musician.
Musician ( ).
,
- , 2 , - . 4 claeses, . .
, - . // "" , .
, aproach . Go :)
. ( ), , . , , - . , . ? , , , - . , , , , , , . , :
-, , , .. . .
-, . , . , , - , , . , , .
-, . , , play() , JazzQuartet, , . ? , , . , , PianistPlay, JazzQuartet.
-, . , , , , . , , . , , , . . , , , , , , , .. , bassistPlay().
Duck Typing:
#include <iostream> #include <memory> #include <vector> class Musician { // Construction // ============ public: template <typename T> Musician(const T& other) : m_concept(new Model<T>(other)) {} Musician(const Musician& other) : m_concept(other.m_concept->copy()) {} Musician(Musician&& x) = default; Musician& operator = (Musician other) { m_concept = std::move(other.m_concept); return *this; } // Duck Typing Interface // ===================== public: // Enable generic functionality friend void play(Musician& musician) { musician.m_concept->play(); } // Invoke external functionality template <typename T> static void invoke_play(T& musician) { play(musician); } // Concept // ======= private: struct Concept { virtual ~Concept() = default; virtual Concept* copy() = 0; virtual void play() = 0; }; // Model // ===== private: template <typename T> struct Model : Concept { T object; Model(const T& other) : object(other) {} Concept* copy() override { return new Model(*this); } void play() override { invoke_play(object); } }; private: std::unique_ptr<Concept> m_concept; }; // Test // ==== class Saxophonist {}; class Pianist {}; class Bassist {}; class Drummer {}; void play(Saxophonist&) { std::cout << "Saxophone\n"; } void play(Pianist&) { std::cout << "Piano\n"; } void play(Bassist&) { std::cout << "Bass\n"; } void play(Drummer&) { std::cout << "Drum\n"; } using JazzQuartet = std::vector<Musician>; void play(JazzQuartet& quartet) { for (auto& musician : quartet) play(musician); } int main() { JazzQuartet quartet; quartet.emplace_back(Saxophonist()); quartet.emplace_back(Pianist()); quartet.emplace_back(Bassist()); quartet.emplace_back(Drummer()); play(quartet); }
- () () . , .
. , , , . , , , .