Use inheritance only for polymorphism in C ++

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.

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.

Any advice on this?

Thank you all in advance!

+4
source share
7 answers

"... 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::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();
}
+8

, Musician . , Pure Abstract Class. , .

, , , , , , , , Musician , , , .

"" , , Musician.

, , , - (, -/?).

+7

. Saxophonist, Pianist, Bassist Drummer "Is-a" Musician.

Musician ( ).

+5

,

- , 2 , - . 4 claeses, . .

, - . // "" , .

, aproach . Go :)

+2

. ( ), , . , , - . , . ? , , , - . , , , , , , . , :

-, , , .. . .

-, . , . , , - , , . , , .

-, . , , play() , JazzQuartet, , . ? , , . , , PianistPlay, JazzQuartet.

-, . , , , , . , , . , , , . . , , , , , , , .. , bassistPlay().

0

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);
}

- () () . , .

0

. , , , . , , , .

-1

All Articles