C++ Inheritance vs Composition for Chess Pieces

ccompositioninheritance

A quick search of this stackexchange shows that in general composition is generally considered more flexible than inheritance but as always it depends on the project etc and there are times when inheritance is the better choice. I want to make a 3D chess game where each piece has a mesh, possibly different animations and so on. In this concrete example it seems like you could argue a case for both approaches am I wrong?

Inheritance would look something like this (with proper constructor etc)

class BasePiece
{
    virtual Squares GetValidMoveSquares() = 0;
    Mesh* mesh;
    // Other fields
}

class Pawn : public BasePiece
{
   Squares GetValidMoveSquares() override;
}

which certainly obeys the "is-a" principle whereas composition would look something like this

class MovementComponent
{
    virtual Squares GetValidMoveSquares() = 0;
}

class PawnMovementComponent
{
     Squares GetValidMoveSquares() override;
}

enum class Type
{
     PAWN,
     BISHOP, //etc
}


class Piece
{
    MovementComponent* movementComponent;
    MeshComponent* mesh;
    Type type;
    // Other fields
 }

Is it more a matter of personal preference or is one approach clearly a smarter choice than the other here?

EDIT: I think I learned something from every answer so I feel bad for only picking one. My final solution will take inspiration from several of the posts here (still working on it). Thanks to everyone who took the time to answer.

Best Answer

At a first glance, your answer pretends the "composition" solution does not use inheritance. But I guess you simply forgot to add this:

class PawnMovementComponent : MovementComponent
{
     Squares GetValidMoveSquares() override;
}

(and more of these derivations, one for each of the six piece types). Now this looks more like the classical "Strategy" pattern, and it is also utilizing inheritance.

Unfortunately, this solution has a flaw: each Piece now holds it's type information redundantly twice:

  • inside the member variable type

  • inside movementComponent (represened by the subtype)

This redundancy is what could really bring you into trouble - a simple class like a Piece should provide a "single source of truth", not two sources.

Of course, you could try to store the type information only in type, and create no child classes of MovementComponent as well. But this design would most probably lead to a huge "switch(type)" statement in the implementation of GetValidMoveSquares. And that is definitely a strong indication for inheritance being the better choice here.

Note in the "inheritance" design, it is quite easy to provide the "type" field in a non-redundant way: add a virtual method GetType() to BasePiece and implement it accordingly in each base class.

Concerning "promotion": I am here with @svidgen, I find the arguments presented in @TheCatWhisperer's answer debatable.

Interpreting "promotion" as a physical exchange of pieces instead of interpreting it as a change of the type of the same piece feels quite more natural to me. So implementing this as in a similar manner - by exchanging one piece by another of a different type - will most probably not cause any huge problems - at least not for the specific case of chess.

Related Topic